Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
pkg://jcifs-0.8.2-1jpp.src.rpm:566555/jcifs-0.8.2.tgz  info  downloads

jcifs_0.8.2/src/jcifs/netbios/Log.java100644      0      0        7064 10025170724  14751 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.util.Hashtable;
import java.util.Enumeration;

/**
 * Provides logging methods specific to the netbios package. Log class
 * members are applied to the Log's mask(set as an arithmetic expression
 * from {@link jcifs.util.Log#setMask(int mask)}) to "flip on" logging of
 * netbios specific information.
 * <p><blockquote><pre>
 *     Log.setMask( Log.EXCEPTIONS +
 *                 jcifs.netbios.Log.SESSION_SERVICE_PACKET_DATA );
 * </pre></blockquote>
 * <p>
 * See the {@link jcifs.util.Log} parent class for details about this
 * logging style.
 *
 * @see       jcifs.util.Log
 */

public class Log extends jcifs.util.Log {

    // supress javadoc constructor summary
    Log() {}

    public static final int NONE                        = 0xFFFFFF0F;
    public static final int ALL                         = 0x000000F0;

/**
 *
 * This mask produces limited netbios name service packet information. See
 * <a href="http://www.cis.ohio-state.edu/rfc/rfc1002.txt">RFC 1002</a>
 * for a detailed description of packet contents and their meaning.
 *
 * @see jcifs.util.Log#setMask(int mask)
 */

    public static final int NAME_SERVICE_PACKET_DATA    = 0x00000010;

    public static final int SESSION_SERVICE_PACKET_DATA = 0x00000020;

/**
 * This mask produces the contents of the netbios address cache.
 *
 * @see jcifs.util.Log#setMask(int mask)
 */

    public static final int ADDRESS_CACHE               = 0x00000040;

/**
 * reserved for this package
 */
    public static final int RESERVED8                   = 0x00000080;

	static void printPacketData( String desc, SessionServicePacket ssp ) {
		try { // why do I have try/catch here?
			if(( SESSION_SERVICE_PACKET_DATA & mask ) == 0 ) {
				return;
			}
            out.println( desc, ssp.toString() );
        } catch( Exception e ) {
            Log.printStackTrace( "jcifs.netbios.Log.printPacketData()", e );
        }
	}

    static void printPacketData( String desc, NameServicePacket nsp ) {
        try {
            if(( NAME_SERVICE_PACKET_DATA & mask ) == 0 ) {
                return;
			}
			out.println( desc, nsp.toString() );
        } catch( Exception e ) {
            Log.printStackTrace( "jcifs.netbios.Log.printPacketData()", e );
        }
    }
    static void printAddressCache( String desc, Hashtable addressCache ) {
        if(( ADDRESS_CACHE & mask ) == 0 )
            return;
        StringBuffer sb = new StringBuffer();
        NbtAddress.CacheEntry ce;
        for( Enumeration e = addressCache.elements(); e.hasMoreElements(); ) {
            ce = (NbtAddress.CacheEntry)e.nextElement();
			sb.append( ' ' ).append( ce.hostName );
			sb.append( ' ' ).append( ce.address ).append( NL );
        }
        out.println( desc, sb.toString() );
    }
}

jcifs_0.8.2/src/jcifs/netbios/NbtException.java100644      0      0        6346 10025170724  16634 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.IOException;

public class NbtException extends IOException {

	// error classes
	public static final int SUCCESS = 0;
	public static final int ERR_NAM_SRVC = 0x01;
	public static final int ERR_SSN_SRVC = 0x02;

	// name service error codes
	public static final int FMT_ERR = 0x1;
	public static final int SRV_ERR = 0x2;
	public static final int IMP_ERR = 0x4;
	public static final int RFS_ERR = 0x5;
	public static final int ACT_ERR = 0x6;
	public static final int CFT_ERR = 0x7;

	// session service error codes
	public static final int CONNECTION_REFUSED    = -1; 
	public static final int NOT_LISTENING_CALLED  = 0x80;
	public static final int NOT_LISTENING_CALLING = 0x81;
	public static final int CALLED_NOT_PRESENT    = 0x82;
	public static final int NO_RESOURCES          = 0x83;
	public static final int UNSPECIFIED           = 0x8F;

	public int errorClass;
	public int errorCode;

	public static String getErrorString( int errorClass, int errorCode ) {
		String result = "";
		switch( errorClass ) {
			case SUCCESS:
				result += "SUCCESS";
				break;
			case ERR_NAM_SRVC:
				result += "ERR_NAM_SRVC/";
				switch( errorCode ) {
					case FMT_ERR:
						result += "FMT_ERR: Format Error";
					default:
						result += "Unknown error code: " + errorCode;
				}
				break;
			case ERR_SSN_SRVC:
				result += "ERR_SSN_SRVC/";
				switch( errorCode ) {
					case CONNECTION_REFUSED:
						result += "Connection refused";
						break;
					case NOT_LISTENING_CALLED:
						result += "Not listening on called name";
						break;
					case NOT_LISTENING_CALLING:
						result += "Not listening for calling name";
						break;
					case CALLED_NOT_PRESENT:
						result += "Called name not present";
						break;
					case NO_RESOURCES:
						result += "Called name present, but insufficient resources";
						break;
					case UNSPECIFIED:
						result += "Unspecified error";
						break;
					default:
						result += "Unknown error code: " + errorCode;
				}
				break;
			default:
				result += "unknown error class: " + errorClass;
		}
		return result;
	}

	public NbtException( int errorClass, int errorCode ) {
		super( getErrorString( errorClass, errorCode ));
		this.errorClass = errorClass;
		this.errorCode = errorCode;
	}
	public String toString() {
		return new String( "errorClass=" + errorClass + ",errorCode=" + errorCode + ",errorString=" + getErrorString( errorClass, errorCode ));
	}
}
jcifs_0.8.2/src/jcifs/netbios/NbtAddress.java100644      0      0       64755 10025170724  16313 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Hashtable;
import jcifs.Config;

/**
 * This class represents a NetBIOS over TCP/IP address. Under normal
 * conditions, users of jCIFS need not be concerned with this class as
 * name resolution and session services are handled internally by the smb package.
 * 
 * <p> Applications can use the methods <code>getLocalHost</code>,
 * <code>getByName</code>, and
 * <code>getAllByAddress</code> to create a new NbtAddress instance. This
 * class is symmetric with {@link java.net.InetAddress}.
 *
 * <p><b>About NetBIOS:</b> The NetBIOS name
 * service is a dynamic distributed service that allows hosts to resolve
 * names by broadcasting a query, directing queries to a server such as
 * Samba or WINS. NetBIOS is currently the primary networking layer for
 * providing name service, datagram service, and session service to the
 * Microsoft Windows platform. A NetBIOS name can be 15 characters long
 * and hosts usually registers several names on the network. From a
 * Windows command prompt you can see
 * what names a host registers with the nbtstat command.
 * <p><blockquote><pre>
 * C:\>nbtstat -a 192.168.1.15
 * 
 *        NetBIOS Remote Machine Name Table
 * 
 *    Name               Type         Status
 * ---------------------------------------------
 * JMORRIS2        <00>  UNIQUE      Registered
 * BILLING-NY      <00>  GROUP       Registered
 * JMORRIS2        <03>  UNIQUE      Registered
 * JMORRIS2        <20>  UNIQUE      Registered
 * BILLING-NY      <1E>  GROUP       Registered
 * JMORRIS         <03>  UNIQUE      Registered
 * 
 * MAC Address = 00-B0-34-21-FA-3B
 * </blockquote></pre>
 * <p> The hostname of this machine is <code>JMORRIS2</code>. It is
 * a member of the group(a.k.a workgroup and domain) <code>BILLING-NY</code>. To
 * obtain an {@link java.net.InetAddress} for a host one might do:
 *
 * <pre>
 *   InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();
 * </pre>
 * <p>From a UNIX platform with Samba installed you can perform similar
 * diagnostics using the <code>nmblookup</code> utility.
 *
 * @author    Michael B. Allen
 * @see       java.net.InetAddress
 * @since     jcifs-0.1
 */ 

public final class NbtAddress {

/*
 * This is a special name that means all hosts. If you wish to find all hosts
 * on a network querying a workgroup group name is the preferred method.
 */ 

	static final String ANY_HOSTS_NAME = "*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";

/** 
 * This is a special name for querying the master browser that serves the
 * list of hosts found in "Network Neighborhood".
 */ 

	public static final String MASTER_BROWSER_NAME = "\u0001\u0002__MSBROWSE__\u0002";

/**
 * A special generic name specified when connecting to a host for which
 * a name is not known. Not all servers respond to this name.
 */

    public static final String SMBSERVER_NAME = "*SMBSERVER     ";

/** 
 * A B node only broadcasts name queries. This is the default if a
 * nameserver such as WINS or Samba is not specified.
 */ 

    public static final int B_NODE = 0;

/**
 * A Point-to-Point node, or P node, unicasts queries to a nameserver
 * only. Natrually the <code>jcifs.netbios.nameserver</code> property must
 * be set.
 */

    public static final int P_NODE = 1;

/** 
 * Try Broadcast queries first, then try to resolve the name using the
 * nameserver.
 */

    public static final int M_NODE = 2;

/** 
 * A Hybrid node tries to resolve a name using the nameserver first. If
 * that fails use the broadcast address. This is the default if a nameserver
 * is provided. This is the behavior of Microsoft Windows machines.
 */ 

    public static final int H_NODE = 3;

	static final int DEFAULT_CACHE_POLICY = 30;
    static final int FOREVER = -1;

    static int cachePolicy;
    static Hashtable addressCache;
    static Hashtable lookupTable;
	static Name unknownName;
    static NbtAddress unknownAddress;
	static byte[] unknownMacAddress = new byte[] {
						(byte)0x00, (byte)0x00, (byte)0x00,
						(byte)0x00, (byte)0x00, (byte)0x00
					};

    static final class CacheEntry {
		Name hostName;
        NbtAddress address;
        long expiration;

        CacheEntry( Name hostName, NbtAddress address, long expiration ) {
			this.hostName = hostName;
            this.address = address;
            this.expiration = expiration;
        }
    }

    static NameServiceClient client;
	static NbtAddress localhost;

    static {
		InetAddress localInetAddress;
		String localHostname;
		Name localName;

    	addressCache = new Hashtable();
    	lookupTable = new Hashtable();
    	cachePolicy = Config.getInt( "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY );

		/* Construct the shared static client object that will
		 * conduct all encoding and decoding of NetBIOS name service
		 * messages as well as socket IO in a synchronized fashon.
		 */

		client = new NameServiceClient();

		/* Create an address to represent failed lookups and cache forever.
		 */

        unknownName = new Name( "0.0.0.0", 0x00, null );
        unknownAddress = new NbtAddress( unknownName, 0, false, B_NODE );
        addressCache.put( unknownName,
						new CacheEntry( unknownName, unknownAddress, FOREVER ));

		/* Determine the InetAddress of the local interface
		 * if one was not specified.
		 */
		localInetAddress = client.laddr;
		if( localInetAddress == null ) {
			try {
				localInetAddress = InetAddress.getLocalHost();
			} catch( UnknownHostException uhe ) {
			}
		}

		/* If a local hostname was not provided a name like
		 * JCIFS34_172_A6 will be dynamically generated for the
		 * client. This is primarily (exclusively?) used as a
		 * CallingName during session establishment.
		 */
		localHostname = Config.getProperty( "jcifs.netbios.hostname", null );
		if( localHostname == null || localHostname.length() == 0 ) {
			byte[] addr = localInetAddress.getAddress();
			localHostname = "JCIFS" +
					( addr[2] & 0xFF ) + "_" +
					( addr[3] & 0xFF ) + "_" +
					Name.toHexChars( (int)( Math.random() * (double)0xFF ));
		}

		/* Create an NbtAddress for the local interface with
		 * the name deduced above possibly with scope applied and
		 * cache it forever.
		 */
		localName = new Name( localHostname, 0x00,
							Config.getProperty( "jcifs.netbios.scope", null ));
		localhost = new NbtAddress( localName,
									localInetAddress.hashCode(),
									false,
									B_NODE,
									false, false, true, false,
									unknownMacAddress );
		cacheAddress( localName, localhost, FOREVER );
    }

    static void cacheAddress( Name hostName, NbtAddress addr ) {
        if( cachePolicy == 0 ) {
            return;
        }
        long expiration = -1;
        if( cachePolicy != FOREVER ) {
            expiration = System.currentTimeMillis() + cachePolicy * 1000;
        }
        cacheAddress( hostName, addr, expiration );
    }
    static void cacheAddress( Name hostName, NbtAddress addr, long expiration ) {
        if( cachePolicy == 0 ) {
            return;
        }
        synchronized( addressCache ) {
            CacheEntry entry = (CacheEntry)addressCache.get( hostName );
            if( entry == null ) {
                entry = new CacheEntry( hostName, addr, expiration );
                addressCache.put( hostName, entry );
            } else {
                entry.address = addr;
                entry.expiration = expiration;
            }
            Log.printAddressCache( "name service address cache", addressCache );
        }
    }
    static void cacheAddressArray( NbtAddress[] addrs ) {
        if( cachePolicy == 0 ) {
            return;
        }
        long expiration = -1;
        if( cachePolicy != FOREVER ) {
            expiration = System.currentTimeMillis() + cachePolicy * 1000;
        }
        synchronized( addressCache ) {
            for( int i = 0; i < addrs.length; i++ ) {
                CacheEntry entry = (CacheEntry)addressCache.get( addrs[i].hostName );
                if( entry == null ) {
                    entry = new CacheEntry( addrs[i].hostName, addrs[i], expiration );
                    addressCache.put( addrs[i].hostName, entry );
                } else {
                    entry.address = addrs[i];
                    entry.expiration = expiration;
                }
            }
            Log.printAddressCache( "name service address cache", addressCache );
        }
    }
    static NbtAddress getCachedAddress( Name hostName ) {
        if( cachePolicy == 0 ) {
            return null;
        }
        synchronized( addressCache ) {
            CacheEntry entry = (CacheEntry)addressCache.get( hostName );
            if( entry != null && entry.expiration < System.currentTimeMillis() &&
												entry.expiration >= 0 ) {
                entry = null;
            }
            return entry != null ? entry.address : null;
        }
    }

    static NbtAddress doNameQuery( Name name, InetAddress svr )
													throws UnknownHostException {
        NbtAddress addr;

		if( name.hexCode == 0x1d && svr == null ) {
			svr = client.baddr; // bit of a hack but saves a lookup
		}
		name.srcHashCode = svr != null ? svr.hashCode() : 0;
		addr = getCachedAddress( name );

        if( addr == null ) {
			/* This was copied amost verbatim from InetAddress.java. See the
			 * comments there for a description of how the lookupTable prevents
			 * redundant queries from going out on the wire.
			 */
			if(( addr = (NbtAddress)checkLookupTable( name )) == null ) {
	            try {
	                addr = client.getByName( name, svr );
	            } catch( UnknownHostException uhe ) {
					addr = unknownAddress;
	            } finally {
	            	cacheAddress( name, addr );
					updateLookupTable( name );
				}
			}
        }
        if( addr == unknownAddress ) {
            throw new UnknownHostException( name.toString() );
        }
        return addr;
    }

	private static Object checkLookupTable( Name name ) {
		Object obj;

		synchronized( lookupTable ) {
			if( lookupTable.containsKey( name ) == false ) {
				lookupTable.put( name, name );
				return null;
			}
			while( lookupTable.containsKey( name )) {
				try {
					lookupTable.wait();
				} catch( InterruptedException e ) {
				}
			}
		}
		obj = getCachedAddress( name );
		if( obj == null ) {
			synchronized( lookupTable ) {
				lookupTable.put( name, name );
			}
		}

		return obj;
	}
	private static void updateLookupTable( Name name ) {
		synchronized( lookupTable ) {
			lookupTable.remove( name );
			lookupTable.notifyAll();
		}
	}

/** 
 * Retrieves the local host address.
 *
 * @throws UnknownHostException This is not likely as the IP returned
 *                    by <code>InetAddress</code> should be available
 */ 

    public static NbtAddress getLocalHost() throws UnknownHostException {
        return localhost;
    }

/** 
 * Determines the address of a host given it's host name. The name can be a NetBIOS name like
 * "freto" or an IP address like "192.168.1.15". It cannot be a DNS name;
 * the analygous {@link jcifs.UniAddress} or {@link java.net.InetAddress}
 * <code>getByName</code> methods can be used for that.
 *
 * @param host hostname to resolve
 * @throws java.net.UnknownHostException if there is an error resolving the name
 */

    public static NbtAddress getByName( String host )
                                        throws UnknownHostException {
        return getByName( host, 0x00, null );
    }

/** 
 * Determines the address of a host given it's host name. NetBIOS
 * names also have a <code>type</code>. Types(aka Hex Codes)
 * are used to distiquish the various services on a host. <a
 * href="../../../nbtcodes.html">Here</a> is
 * a fairly complete list of NetBIOS hex codes. Scope is not used but is
 * still functional in other NetBIOS products and so for completeness it has been
 * implemented. A <code>scope</code> of <code>null</code> or <code>""</code>
 * signifies no scope.
 *
 * @param host the name to resolve
 * @param type the hex code of the name
 * @param scope the scope of the name
 * @throws java.net.UnknownHostException if there is an error resolving the name
 */

    public static NbtAddress getByName( String host,
                                        int type,
                                        String scope )
                                        throws UnknownHostException {

		return getByName( host, type, scope, null );
	}

/* 
 * The additional <code>svr</code> parameter specifies the address to
 * query. This might be the address of a specific host, a name server,
 * or a broadcast address.
 */ 

    public static NbtAddress getByName( String host,
                                        int type,
                                        String scope,
										InetAddress svr )
                                        throws UnknownHostException {

        if( host == null || host.length() == 0 ) {
            return getLocalHost();
        }
        if( !Character.isDigit( host.charAt(0) )) {
            return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
        } else {
            int IP = 0x00;
            int hitDots = 0;
            char[] data = host.toCharArray();

            for( int i = 0; i < data.length; i++ ) {
                char c = data[i];
                if( c < 48 || c > 57 ) {
                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                }
                int b = 0x00;
                while( c != '.' ) {
                    if( c < 48 || c > 57 ) {
                        return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                    }
                    b = b * 10 + c - '0';

                    if( ++i >= data.length )
                        break;

                    c = data[i];
                }
                if( b > 0xFF ) {
                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                }
                IP = ( IP << 8 ) + b;
                hitDots++;
            }
            if( hitDots != 4 || host.endsWith( "." )) {
                return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
            }
            return new NbtAddress( unknownName, IP, false, B_NODE );
        }
    }

/**
 * Retrieve all addresses of a host by it's address. NetBIOS hosts can
 * have many names for a given IP address. The name and IP address make the
 * NetBIOS address. This provides a way to retrieve the other names for a
 * host with the same IP address.
 *
 * @param host hostname to lookup all addresses for
 * @throws java.net.UnknownHostException if there is an error resolving the name
 */


    public static NbtAddress[] getAllByAddress( String host )
												throws UnknownHostException {
        return getAllByAddress( getByName( host, 0x00, null ));
    }


/**
 * Retrieve all addresses of a host by it's address. NetBIOS hosts can
 * have many names for a given IP address. The name and IP address make
 * the NetBIOS address. This provides a way to retrieve the other names
 * for a host with the same IP address.  See {@link #getByName}
 * for a description of <code>type</code>
 * and <code>scope</code>.
 *
 * @param host hostname to lookup all addresses for
 * @param type the hexcode of the name
 * @param scope the scope of the name
 * @throws java.net.UnknownHostException if there is an error resolving the name
 */


    public static NbtAddress[] getAllByAddress( String host,
                                        int type,
                                        String scope )
                                        throws UnknownHostException {
        return getAllByAddress( getByName( host, type, scope ));
    }


/**
 * Retrieve all addresses of a host by it's address. NetBIOS hosts can
 * have many names for a given IP address. The name and IP address make the
 * NetBIOS address. This provides a way to retrieve the other names for a
 * host with the same IP address.
 *
 * @param addr the address to query
 * @throws UnknownHostException if address cannot be resolved
 */

    public static NbtAddress[] getAllByAddress( NbtAddress addr )
												throws UnknownHostException {
        try {
            NbtAddress[] addrs = client.getNodeStatus( addr );
            cacheAddressArray( addrs );
            return addrs;
        } catch( UnknownHostException uhe ) {
            throw new UnknownHostException( "no name with type 0x" +
							Name.toHexChars( addr.hostName.hexCode ) +
							((( addr.hostName.scope == null ) ||
							( addr.hostName.scope.length() == 0 )) ?
							" with no scope" : " with scope " + addr.hostName.scope ) +
							" for host " + addr.getHostAddress() );
        }
    }

    Name hostName;
    int address, nodeType;
    boolean groupName,
		isBeingDeleted,
    	isInConflict,
    	isActive,
    	isPermanent,
    	isDataFromNodeStatus;
    byte[] macAddress;
	String calledName;

    NbtAddress( Name hostName, int address, boolean groupName, int nodeType ) {
        this.hostName = hostName;
        this.address = address;
        this.groupName = groupName;
        this.nodeType = nodeType;
	}

    NbtAddress( Name hostName,
                int address,
                boolean groupName,
                int nodeType,
                boolean isBeingDeleted,
                boolean isInConflict,
                boolean isActive,
                boolean isPermanent,
                byte[] macAddress ) {

/* The NodeStatusResponse.readNodeNameArray method may also set this
 * information. These two places where node status data is populated should
 * be consistent. Be carefull!
 */
        this.hostName = hostName;
        this.address = address;
        this.groupName = groupName;
        this.nodeType = nodeType;
        this.isBeingDeleted = isBeingDeleted;
        this.isInConflict = isInConflict;
        this.isActive = isActive;
        this.isPermanent = isPermanent;
        this.macAddress = macAddress;
        isDataFromNodeStatus = true;
    }

/* Guess next called name to try for session establishment. These
 * methods are used by the smb package.
 */

	public String firstCalledName() {

		calledName = hostName.name;

		if( Character.isDigit( calledName.charAt( 0 ))) {
			int i, len, dots;
			char[] data;

			i = dots = 0;                    /* quick IP address validation */
			len = calledName.length();
			data = calledName.toCharArray();
			while( i < len && Character.isDigit( data[i++] )) {
				if( i == len && dots == 3 ) {
					// probably an IP address
					calledName = SMBSERVER_NAME;
					break;
				}
				if( i < len && data[i] == '.' ) {
					dots++;
					i++;
				}
			}
		} else if( hostName.hexCode == 0x1D ) {
			calledName = SMBSERVER_NAME;
		}

		return calledName;
    }
	public String nextCalledName() {

		if( calledName == hostName.name ) {
			calledName = SMBSERVER_NAME;
		} else if( calledName == SMBSERVER_NAME ) {
			NbtAddress[] addrs;

			try {
				addrs = client.getNodeStatus( this );
				if( hostName.hexCode == 0x1D ) {
					for( int i = 0; i < addrs.length; i++ ) {
						if( addrs[i].hostName.hexCode == 0x20 ) {
							return addrs[i].hostName.name;
						}
					}
					return null;
				} else if( isDataFromNodeStatus ) {
					/* 'this' has been updated and should now
					 * have a real NetBIOS name
					 */
					calledName = null;
					return hostName.name;
				}
			} catch( UnknownHostException uhe ) {
				calledName = null;
			}
		} else {
			calledName = null;
		}

		return calledName;
	}

/* 
 * There are three degrees of state that any NbtAddress can have.
 * 
 * 1) IP Address - If a dot-quad IP string is used with getByName (or used
 * to create an NbtAddress internal to this netbios package), no query is
 * sent on the wire and the only state this object has is it's IP address
 * (but that's enough to connect to a host using *SMBSERVER for CallingName).
 * 
 * 2) IP Address, NetBIOS name, nodeType, groupName - If however a
 * legal NetBIOS name string is used a name query request will retreive
 * the IP, node type, and whether or not this NbtAddress represents a
 * group name. This degree of state can be obtained with a Name Query
 * Request or Node Status Request.
 * 
 * 3) All - The NbtAddress will be populated with all state such as mac
 * address, isPermanent, isBeingDeleted, ...etc. This information can only
 * be retrieved with the Node Status request.
 * 
 * The degree of state that an NbtAddress has is dependant on how it was
 * created and what is required of it. The second degree of state is the
 * most common. This is the state information that would be retrieved from
 * WINS for example. Natrually it is not practical for every NbtAddress
 * to be populated will all state requiring a Node Status on every host
 * encountered. The below methods allow state to be populated when requested
 * in a lazy fashon.
 */ 

    void checkData() throws UnknownHostException {
        if( hostName == unknownName ) {
        	getAllByAddress( this );
        }
    }
    void checkNodeStatusData() throws UnknownHostException {
        if( isDataFromNodeStatus == false ) {
        	getAllByAddress( this );
        }
    }

/**
 * Determines if the address is a group address. This is also
 * known as a workgroup name or group name.
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */

    public boolean isGroupAddress() throws UnknownHostException {
        checkData();
        return groupName;
    }

/** 
 * Checks the node type of this address.
 * @return {@link jcifs.netbios.NbtAddress#B_NODE},
 * {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE},
 * {@link jcifs.netbios.NbtAddress#H_NODE}
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */ 

    public int getNodeType() throws UnknownHostException {
        checkData();
        return nodeType;
    }

/** 
 * Determines if this address in the process of being deleted.
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */ 

    public boolean isBeingDeleted() throws UnknownHostException {
        checkNodeStatusData();
        return isBeingDeleted;
    }

/** 
 * Determines if this address in conflict with another address.
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */ 

    public boolean isInConflict() throws UnknownHostException {
        checkNodeStatusData();
        return isInConflict;
    }

/** 
 * Determines if this address is active.
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */ 

    public boolean isActive() throws UnknownHostException {
        checkNodeStatusData();
        return isActive;
    }

/** 
 * Determines if this address is set to be permanent.
 *
 * @throws UnknownHostException if the host cannot be resolved to find out.
 */ 

    public boolean isPermanent() throws UnknownHostException {
        checkNodeStatusData();
        return isPermanent;
    }

/** 
 * Retrieves the MAC address of the remote network interface. Samba returns all zeros.
 *
 * @return the MAC address as an array of six bytes
 * @throws UnknownHostException if the host cannot be resolved to
 * determine the MAC address.
 */ 

    public byte[] getMacAddress() throws UnknownHostException {
        checkNodeStatusData();
        return macAddress;
    }

/** 
 * The hostname of this address. If the hostname is null the local machines
 * IP address is returned.
 *
 * @return the text representation of the hostname associated with this address
 */ 

    public String getHostName() {
        try {
			checkData();
        } catch( UnknownHostException uhe ) {
            return getHostAddress();
        }
        return hostName.name;
    }


/** 
 * Returns the raw IP address of this NbtAddress. The result is in network
 * byte order: the highest order byte of the address is in getAddress()[0].
 *
 * @return a four byte array
 */ 

    public byte[] getAddress() {    
        byte[] addr = new byte[4];

        addr[0] = (byte)(( address >>> 24 ) & 0xFF );
        addr[1] = (byte)(( address >>> 16 ) & 0xFF );
        addr[2] = (byte)(( address >>> 8 ) & 0xFF );
        addr[3] = (byte)( address & 0xFF );
        return addr;
    }

/** 
 * To convert this address to an <code>InetAddress</code>.
 *
 * @return the {@link java.net.InetAddress} representation of this address.
 */ 

    public InetAddress getInetAddress() throws UnknownHostException {
        return InetAddress.getByName( getHostAddress() );
    }

/** 
 * Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".
 */ 

    public String getHostAddress() {    
        return (( address >>> 24 ) & 0xFF ) + "." +
            (( address >>> 16 ) & 0xFF ) + "." +
            (( address >>> 8 ) & 0xFF ) + "." +
            (( address >>> 0 ) & 0xFF );
    }

/**
 * Returned the hex code associated with this name(e.g. 0x20 is for the file service)
 */

	public int getNameType() {
		return hostName.hexCode;
	}

/** 
 * Returns a hashcode for this IP address. The hashcode comes from the IP address
 * and is not generated from the string representation. So because NetBIOS nodes
 * can have many names, all names associated with an IP will have the same
 * hashcode.
 */ 

    public int hashCode() {
        return address;
    }

/** 
 * Determines if this address is equal two another. Only the IP Addresses
 * are compared. Similar to the {@link #hashCode} method, the comparison
 * is based on the integer IP address and not the string representation.
 */ 

    public boolean equals( Object obj ) {
        return ( obj != null ) && ( obj instanceof NbtAddress ) &&
										( ((NbtAddress)obj).address == address );
    }

/** 
 * Returns the {@link java.lang.String} representaion of this address.
 */ 

    public String toString() {
        return hostName.toString() + "/" + getHostAddress();
    }
}
jcifs_0.8.2/src/jcifs/netbios/SocketOutputStream.java100644      0      0        5437 10025170724  20057 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.FilterOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import jcifs.util.Log;

class SocketOutputStream extends FilterOutputStream {

	private static int DEFAULT_BUFR_SIZE = 4400;

	private byte[] bufr;
	private int count, writeSize;

	SocketOutputStream( OutputStream out ) {
		this( out, DEFAULT_BUFR_SIZE );
	}
	SocketOutputStream( OutputStream out, int size ) {
		super( out );
		writeSize = jcifs.Config.getInt( "jcifs.netbios.client.writeSize", size );
		if( writeSize <= 0 ) {
			throw new IllegalArgumentException( "buffer size <= 0" );
		} else if( writeSize > SessionServicePacket.MAX_MESSAGE_SIZE ) {
			throw new IllegalArgumentException( "buffer exceeds max netbios message size" );
		}
		writeSize += 4;
		bufr = new byte[writeSize];
		bufr[0] = (byte)SessionServicePacket.SESSION_MESSAGE;
		count = 4;
	}

	public synchronized void write( int b ) throws IOException {
		if( count >= bufr.length ) {
			flush();
		}
		bufr[count++] = (byte)b;
	}
	public synchronized void write( byte[] b, int off, int len ) throws IOException {
		if(( len + 4 ) > bufr.length ) {
			Log.println( Log.WARNINGS, "session service warning",
							"write len exceeds pre-allocated buffer size; performance " +
							"will suffer: len=" + len + ",writeSize=" + writeSize );
			flush();
			byte[] tmp = bufr;
			bufr = new byte[len + 4]; /* at least mantain a permainent fixed size buffer */
			System.arraycopy( b, off, bufr, count, len ); /* doah! */
			count += len;
			flush();
			bufr = tmp;
			return;
		}
		if( len > bufr.length - count ) {
			flush();
		}
		System.arraycopy( b, off, bufr, count, len );
		count += len;
	}
	public synchronized void flush() throws IOException {
		if( count == 4 ) {
			return;
		}
		int n = count - 4;
		bufr[1] = (byte)(( n & 0x010000 ) == 0x00 ? 0x00 : 0x01 ); 
		bufr[2] = (byte)(( n >> 8 ) & 0xFF ); 
		bufr[3] = (byte)( n & 0xFF ); 
		out.write( bufr, 0, count );
		out.flush();
		count = 4;
	}
}
jcifs_0.8.2/src/jcifs/netbios/NameQueryRequest.java100644      0      0        2713 10025170724  17503 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

class NameQueryRequest extends NameServicePacket {

	NameQueryRequest( Name name ) {
		questionName = name;
		questionType = NB;
	}

	int writeBodyWireFormat( byte[] dst, int dstIndex ) {
		return writeQuestionSectionWireFormat( dst, dstIndex );
	}
	int readBodyWireFormat( byte[] src, int srcIndex ) {
		return readQuestionSectionWireFormat( src, srcIndex );
	}
	int writeRDataWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readRDataWireFormat( byte[] src, int srcIndex ) {
		return 0;
	}
	public String toString() {
		return new String( "NameQueryRequest[" +
			super.toString() + "]" );
	}
}
jcifs_0.8.2/src/jcifs/netbios/Name.java100644      0      0       14444 10025170724  15130 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <jcifs at samba dot org>
 *                     "Christopher R. Hertel" <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 jcifs.netbios;

import java.io.UnsupportedEncodingException;
import jcifs.Config;

class Name {

    static final char[] HEX_DIGITS = { 
    '0' , '1' , '2' , '3' , '4' , '5' ,
    '6' , '7' , '8' , '9' , 'A' , 'B' ,
    'C' , 'D' , 'E' , 'F'
    };

    static String toHexChars( int val ) {
        int len = 2;
        char[] tmp = new char[2];
        while( len > 0 ) {
            tmp[ len - 1 ] = HEX_DIGITS[val & 0x000F];
            if( val != 0 ) {
                val >>>= 4;
            }
            len--;
        }
        return new String( tmp );
    }

	static final int TYPE_OFFSET = 31;
	static final int SCOPE_OFFSET = 33;

	static String defaultScope = Config.getProperty( "jcifs.netbios.scope" );
	static String encoding = Config.getProperty( "jcifs.netbios.encoding", "ISO8859_1" );

    String name, scope;
    int hexCode;
	int srcHashCode; /* srcHashCode must be set by name resolution
					  * routines before entry into addressCache
					  */

	Name() {
	}
    Name( String name, int hexCode, String scope ) {
	    if( name.length() > 15 ) {
			name = name.substring( 0, 15 );
		}
		this.name = name.toUpperCase();
		this.hexCode = hexCode;
		this.scope = scope != null && scope.length() > 0 ? scope : defaultScope;
		this.srcHashCode = 0;
    }

	int writeWireFormat( byte[] dst, int dstIndex ) {
        // write 0x20 in first byte
        dst[dstIndex] = 0x20;

        // write name
		try {
	        byte tmp[] = name.getBytes( Name.encoding );
	        int i;
	        for( i = 0; i < tmp.length; i++ ) {
	            dst[dstIndex + ( 2 * i + 1 )] = (byte)((( tmp[i] & 0xF0 ) >> 4 ) + 0x41 );
	            dst[dstIndex + ( 2 * i + 2 )] = (byte)(( tmp[i] & 0x0F ) + 0x41 );
	        }
	        for( ; i < 15; i++ ) {
	            dst[dstIndex + ( 2 * i + 1 )] = (byte)0x43;
	            dst[dstIndex + ( 2 * i + 2 )] = (byte)0x41;
	        }
	        dst[dstIndex + TYPE_OFFSET] = (byte)((( hexCode & 0xF0 ) >> 4 ) + 0x41 );
	        dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( hexCode & 0x0F ) + 0x41 );
		} catch( UnsupportedEncodingException uee ) {
		}
		return SCOPE_OFFSET + writeScopeWireFormat( dst, dstIndex + SCOPE_OFFSET );
	}

	int readWireFormat( byte[] src, int srcIndex ) {

        byte tmp[] = new byte[SCOPE_OFFSET];
        int length = 15;
        for( int i = 0; i < 15; i++ ) {
            tmp[i] = (byte)((( src[srcIndex + ( 2 * i + 1 )] & 0xFF ) - 0x41 ) << 4 );
            tmp[i] |= (byte)((( src[srcIndex + ( 2 * i + 2 )] & 0xFF ) - 0x41 ) & 0x0F );
            if( tmp[i] != (byte)' ' ) {
                length = i + 1;
            }
        }
		try {
        	name = new String( tmp, 0, length, Name.encoding );
		} catch( UnsupportedEncodingException uee ) {
		}
        hexCode = (( src[srcIndex + TYPE_OFFSET] & 0xFF ) - 0x41 ) << 4;
        hexCode |= (( src[srcIndex + TYPE_OFFSET + 1] & 0xFF ) - 0x41 ) & 0x0F;
		return SCOPE_OFFSET + readScopeWireFormat( src, srcIndex + SCOPE_OFFSET );
    }
	int writeScopeWireFormat( byte[] dst, int dstIndex ) {
		if( scope == null ) {
			dst[dstIndex] = (byte)0x00;
			return 1;
		}

        // copy new scope in
        dst[dstIndex++] = (byte)'.';
		try {
        	System.arraycopy( scope.getBytes( encoding ), 0, dst, dstIndex, scope.length() );
		} catch( UnsupportedEncodingException uee ) {
		}
		dstIndex += scope.length();

		dst[dstIndex++] = (byte)0x00;

        // now go over scope backwards converting '.' to label length

		int i = dstIndex - 2;
		int e = i - scope.length();
		int c = 0;

		do {
            if( dst[i] == '.' ) {
                dst[i] = (byte)c;
                c = 0;
            } else {
                c++;
            }
		} while( i-- > e );
		return scope.length() + 2;
    }
	int readScopeWireFormat( byte[] src, int srcIndex ) {
		int start = srcIndex;
		int n;
		StringBuffer sb;

		if(( n = src[srcIndex++] & 0xFF ) == 0 ) {
			scope = null;
			return 1;
		}

		try {
			sb = new StringBuffer( new String( src, srcIndex, n, Name.encoding ));
			srcIndex += n;
			while(( n = src[srcIndex++] & 0xFF ) != 0 ) {
				sb.append( '.' ).append( new String( src, srcIndex, n, Name.encoding ));
				srcIndex += n;
			}
			scope = sb.toString();
		} catch( UnsupportedEncodingException uee ) {
		}

		return srcIndex - start;
	}

    public int hashCode() {
		int result;

		result = name.hashCode();
		result += 65599 * hexCode;
		result += 65599 * srcHashCode; /* hashCode is different depending
										* on where it came from
										*/
		if( scope != null && scope.length() != 0 ) {
			result += scope.hashCode();
		}
        return result;
    }
    public boolean equals( Object obj ) {
		Name n;

        if( !( obj instanceof Name )) {
            return false;
        }
        n = (Name)obj;
		if( scope == null && n.scope == null ) {
			return name.equals( n.name ) && hexCode == n.hexCode;
		}
		return name.equals( n.name ) && hexCode == n.hexCode && scope.equals( n.scope );
    }
    public String toString() {
		StringBuffer sb = new StringBuffer();
		String n = name;

        // fix MSBROWSE name
		if( n == null ) {
			n = "null";
        } else if( n.charAt( 0 ) == 0x01 ) {
            char c[] = n.toCharArray();
            c[0] = '.';
            c[1] = '.';
            c[14] = '.';
            n = new String( c );
        }

        sb.append( n ).append( "<" ).append( toHexChars( hexCode )).append( ">" );
        if( scope != null ) {
            sb.append( "." ).append( scope );
        }
        return sb.toString();
    }
}

jcifs_0.8.2/src/jcifs/netbios/NodeStatusResponse.java100644      0      0       13062 10025170724  20053 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.UnsupportedEncodingException;

class NodeStatusResponse extends NameServicePacket {

	NbtAddress queryAddress;

	int numberOfNames;
	NbtAddress[] addressArray;
	byte[] macAddress;
	byte[] stats;

	/* It is a little awkward but prudent to pass the quering address
	 * so that it may be included in the list of results. IOW we do
	 * not want to create a new NbtAddress object for this particular
	 * address from which the query is constructed, we want to populate
     * the data of the existing address that should be one of several
	 * returned by the node status.
	 */

	NodeStatusResponse( NbtAddress queryAddress ) {
		this.queryAddress = queryAddress;
		recordName = new Name();
        macAddress = new byte[6];
	}

	int writeBodyWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readBodyWireFormat( byte[] src, int srcIndex ) {
		return readResourceRecordWireFormat( src, srcIndex );
	}
	int writeRDataWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readRDataWireFormat( byte[] src, int srcIndex ) {
		int start = srcIndex;
		numberOfNames = src[srcIndex] & 0xFF;
		int namesLength = numberOfNames * 18;
		int statsLength = rDataLength - namesLength - 1;
		numberOfNames = src[srcIndex++] & 0xFF;
		// gotta read the mac first so we can populate addressArray with it
        System.arraycopy( src, srcIndex + namesLength, macAddress, 0, 6 );
		srcIndex += readNodeNameArray( src, srcIndex );
		stats = new byte[statsLength];
		System.arraycopy( src, srcIndex, stats, 0, statsLength );
		srcIndex += statsLength;
		return srcIndex - start;
	}
    private int readNodeNameArray( byte[] src, int srcIndex ) {
		int start = srcIndex;

		addressArray = new NbtAddress[numberOfNames];

        String n;
        int hexCode;
        String scope = queryAddress.hostName.scope;
        boolean groupName;
        int ownerNodeType;
        boolean isBeingDeleted;
        boolean isInConflict;
        boolean isActive;
        boolean isPermanent;
        int j;
        boolean addrFound = false;

		try {
	        for( int i = 0; i < numberOfNames; srcIndex += 18, i++ ) {
	            for( j = srcIndex + 14; src[j] == 0x20; j-- )
	                ;
		        n = new String( src, srcIndex, j - srcIndex + 1, Name.encoding );
	            hexCode          =    src[srcIndex + 15] & 0xFF;
	            groupName        = (( src[srcIndex + 16] & 0x80 ) == 0x80 ) ? true : false;
	            ownerNodeType    =  ( src[srcIndex + 16] & 0x60 ) >> 5;
	            isBeingDeleted   = (( src[srcIndex + 16] & 0x10 ) == 0x10 ) ? true : false;
	            isInConflict     = (( src[srcIndex + 16] & 0x08 ) == 0x08 ) ? true : false;
	            isActive         = (( src[srcIndex + 16] & 0x04 ) == 0x04 ) ? true : false;
	            isPermanent      = (( src[srcIndex + 16] & 0x02 ) == 0x02 ) ? true : false;
	
	/* The NbtAddress object used to query this node will be in the list
	 * returned by the Node Status. A new NbtAddress object should not be
	 * created for it because the original is potentially being actively
	 * referenced by other objects. We must populate the existing object's
	 * data explicitly (and carefully).
	 */
	            if( !addrFound && queryAddress.hostName.hexCode == hexCode &&
						( queryAddress.hostName == NbtAddress.unknownName ||
						queryAddress.hostName.name.equals( n ))) {
	
					if( queryAddress.hostName == NbtAddress.unknownName ) {
	                	queryAddress.hostName = new Name( n, hexCode, scope );
					}
	                queryAddress.groupName = groupName;
	                queryAddress.nodeType = ownerNodeType;
	                queryAddress.isBeingDeleted = isBeingDeleted;
	                queryAddress.isInConflict = isInConflict;
	                queryAddress.isActive = isActive;
	                queryAddress.isPermanent = isPermanent;
	                queryAddress.macAddress = macAddress;
	                queryAddress.isDataFromNodeStatus = true;
	                addrFound = true;
	                addressArray[i] = queryAddress;
	            } else {
	                addressArray[i] = new NbtAddress( new Name( n, hexCode, scope ),
	                                        queryAddress.address,
	                                        groupName,
	                                        ownerNodeType,
	                                        isBeingDeleted,
	                                        isInConflict,
	                                        isActive,
	                                        isPermanent,
	                                        macAddress );
	            }
	        }
		} catch( UnsupportedEncodingException uee ) {
		}
        return srcIndex - start;
    }
	public String toString() {
		return new String( "NodeStatusResponse[" +
			super.toString() + "]" );
	}
}

jcifs_0.8.2/src/jcifs/netbios/SessionServicePacket.java100644      0      0        7440 10025170724  20322 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.IOException;
import java.io.InputStream;

abstract class SessionServicePacket { 

	// session service packet types 
	static final int SESSION_MESSAGE = 0x00; 
	static final int SESSION_REQUEST = 0x81; 
	static final int POSITIVE_SESSION_RESPONSE = 0x82; 
	static final int NEGATIVE_SESSION_RESPONSE = 0x83; 
	static final int SESSION_RETARGET_RESPONSE = 0x84; 
	static final int SESSION_KEEP_ALIVE = 0x85; 

	static final int MAX_MESSAGE_SIZE = 0x0001FFFF;
	static final int HEADER_LENGTH = 4;

	static void writeInt2( int val, byte[] dst, int dstIndex ) {
		dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
		dst[dstIndex] = (byte)( val & 0xFF );
	}
	static void writeInt4( int val, byte[] dst, int dstIndex ) {
		dst[dstIndex++] = (byte)(( val >> 24 ) & 0xFF );
		dst[dstIndex++] = (byte)(( val >> 16 ) & 0xFF );
		dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
		dst[dstIndex] = (byte)( val & 0xFF );
	}
	static int readInt2( byte[] src, int srcIndex ) {
		return (( src[srcIndex] & 0xFF ) << 8 ) +
				( src[srcIndex + 1] & 0xFF );
	}
	static int readInt4( byte[] src, int srcIndex ) {
		return (( src[srcIndex] & 0xFF ) << 24 ) +
				(( src[srcIndex + 1] & 0xFF ) << 16 ) +
				(( src[srcIndex + 2] & 0xFF ) << 8 ) +
				( src[srcIndex + 3] & 0xFF );
	}
	static int readLength( byte[] src, int srcIndex ) {
		srcIndex++;
		return (( src[srcIndex++] & 0x01 ) << 16 ) +
				(( src[srcIndex++] & 0xFF ) << 8 ) +
				( src[srcIndex++] & 0xFF );
	}
	static int readPacketType( InputStream in,
									byte[] buffer,
									int bufferIndex )
									throws IOException {
		int n;
		if(( n = in.read( buffer, bufferIndex, HEADER_LENGTH )) != HEADER_LENGTH ) {
			if( n == -1 ) {
				return -1;
			}
			throw new IOException( "unexpected EOF reading netbios session header" );
		}
		int t = buffer[bufferIndex] & 0xFF;
		return t;
	}

	int type, length;

	int writeWireFormat( byte[] dst, int dstIndex ) {
		length = writeTrailerWireFormat( dst, dstIndex + HEADER_LENGTH );
		writeHeaderWireFormat( dst, dstIndex );
		return HEADER_LENGTH + length;
	}
	int readWireFormat( InputStream in, byte[] buffer, int bufferIndex ) throws IOException {
		readHeaderWireFormat( in, buffer, bufferIndex );
		return HEADER_LENGTH + readTrailerWireFormat( in, buffer, bufferIndex );
	}
	int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
		dst[dstIndex++] = (byte)type;
		if( length > 0x0000FFFF ) {
			dst[dstIndex] = (byte)0x01;
		}
		dstIndex++;
		writeInt2( length, dst, dstIndex );
		return HEADER_LENGTH;
	}
	int readHeaderWireFormat( InputStream in,
								byte[] buffer,
								int bufferIndex )
								throws IOException {
		type = buffer[bufferIndex++] & 0xFF;
		length = (( buffer[bufferIndex] & 0x01 ) << 16 ) + readInt2( buffer, bufferIndex + 1 );
		return HEADER_LENGTH;
	}

	abstract int writeTrailerWireFormat( byte[] dst, int dstIndex );
	abstract int readTrailerWireFormat( InputStream in,
								byte[] buffer,
								int bufferIndex )
								throws IOException;
} 
jcifs_0.8.2/src/jcifs/netbios/SessionRequestPacket.java100644      0      0        3623 10025170724  20351 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.IOException;
import java.io.InputStream;

class SessionRequestPacket extends SessionServicePacket {

	Name calledName, callingName;

	SessionRequestPacket() {
		calledName = new Name();
		callingName = new Name();
	}
	SessionRequestPacket( Name calledName, Name callingName ) {
		type = SESSION_REQUEST;
		this.calledName = calledName;
		this.callingName = callingName;
	}
	int writeTrailerWireFormat( byte[] dst, int dstIndex ) {
		int start = dstIndex;
		dstIndex += calledName.writeWireFormat( dst, dstIndex );
		dstIndex += callingName.writeWireFormat( dst, dstIndex );
		return dstIndex - start;
	}
	int readTrailerWireFormat( InputStream in,
							byte[] buffer,
							int bufferIndex )
							throws IOException {
		int start = bufferIndex;
		if( in.read( buffer, bufferIndex, length ) != length ) {
			throw new IOException( "invalid session request wire format" );
		}
		bufferIndex += calledName.readWireFormat( buffer, bufferIndex );
		bufferIndex += callingName.readWireFormat( buffer, bufferIndex );
		return bufferIndex - start;
	}
}
jcifs_0.8.2/src/jcifs/netbios/NameQueryResponse.java100644      0      0        3370 10025170725  17652 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

class NameQueryResponse extends NameServicePacket {

	NbtAddress addrEntry;

	NameQueryResponse() {
		recordName = new Name();
	}

	int writeBodyWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readBodyWireFormat( byte[] src, int srcIndex ) {
		return readResourceRecordWireFormat( src, srcIndex );
	}
	int writeRDataWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readRDataWireFormat( byte[] src, int srcIndex ) {
		if( resultCode != 0 || opCode != QUERY ) {
			return 0;
		}
		boolean groupName = (( src[srcIndex] & 0x80 ) == 0x80 ) ? true : false;
		int nodeType = ( src[srcIndex] & 0x60 ) >> 5;
		srcIndex += 2;
		int address = readInt4( src, srcIndex );
		addrEntry = new NbtAddress( recordName, address, groupName, nodeType );
		return 6;
	}
	public String toString() {
		return new String( "NameQueryResponse[" +
			super.toString() +
			",addrEntry=" + addrEntry + "]" );
	}
}
jcifs_0.8.2/src/jcifs/netbios/SocketInputStream.java100644      0      0        5324 10025170725  17652 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.InputStream;
import java.io.IOException;

class SocketInputStream extends InputStream {

	private static final int TMP_BUFFER_SIZE = 256;
	private InputStream in;
	private SessionServicePacket ssp;
	private int tot, bip, n;
	private byte[] header, tmp;

	SocketInputStream( InputStream in ) {
		this.in = in;
		header = new byte[4];
		tmp = new byte[TMP_BUFFER_SIZE];
	}

	public synchronized int read() throws IOException {
		if( read( tmp, 0, 1 ) < 0 ) {
			return -1;
		}
		return tmp[0] & 0xFF;
	}
	public synchronized int read( byte[] b ) throws IOException {
		return read( b, 0, b.length );
	}

	/* This method will not return until len bytes have been read
	 * or the stream has been closed.
	 */

	public synchronized int read( byte[] b, int off, int len ) throws IOException {
		if( len == 0 ) {
			return 0;
		}
		tot = 0;

		while( true ) {
			while( bip > 0 ) {
				n = in.read( b, off, Math.min( len, bip ));
				if( n == -1 ) {
					return tot > 0 ? tot : -1;
				}
				tot += n;
				off += n;
				len -= n;
				bip -= n;
				if( len == 0 ) {
					return tot;
				}
			}

			switch( SessionServicePacket.readPacketType( in, header, 0 )) {
				case SessionServicePacket.SESSION_KEEP_ALIVE:
					break;
				case SessionServicePacket.SESSION_MESSAGE:
					bip = SessionServicePacket.readLength( header, 0 );
					break;
				case -1:
					if( tot > 0 ) {
						return tot;
					}
					return -1;
			}
		}
	}
	public synchronized long skip( long numbytes ) throws IOException {
		if( numbytes <= 0 ) {
			return 0;
		}
		long n = numbytes;
		while( n > 0 ) {
			int r = read( tmp, 0, (int)Math.min( (long)TMP_BUFFER_SIZE, n ));
			if (r < 0) {
				break;
			}
			n -= r;
		}
		return numbytes - n;
	}
	public int available() throws IOException {
		if( bip > 0 ) {
			return bip;
		}
		return in.available();
	}
	public void close() throws IOException {
		in.close();
	}
}

jcifs_0.8.2/src/jcifs/netbios/SessionRetargetResponsePacket.java100644      0      0        3236 10025170725  22216 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.io.IOException;
import java.io.InputStream;

class SessionRetargetResponsePacket extends SessionServicePacket {

	NbtAddress retargetAddress;
	int retargetPort;

	SessionRetargetResponsePacket() {
		type = SESSION_RETARGET_RESPONSE;
		length = 6;
	}

	int writeTrailerWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readTrailerWireFormat( InputStream in,
							byte[] buffer,
							int bufferIndex )
							throws IOException {
		if( in.read( buffer, bufferIndex, length ) != length ) {
			throw new IOException( "unexpected EOF reading netbios retarget session response" );
		}
		int addr = readInt4( buffer, bufferIndex );
		bufferIndex += 4;
		retargetAddress = new NbtAddress( null, addr, false, NbtAddress.B_NODE );
		retargetPort = readInt2( buffer, bufferIndex );
		return length;
	}
}
jcifs_0.8.2/src/jcifs/netbios/NodeStatusRequest.java100644      0      0        3163 10025170725  17667 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

class NodeStatusRequest extends NameServicePacket {

	NodeStatusRequest( Name name ) {
		questionName = name;
		questionType = NBSTAT;
		isRecurDesired = false;
		isBroadcast = false;
	}

	int writeBodyWireFormat( byte[] dst, int dstIndex ) {
		int tmp = questionName.hexCode;
		questionName.hexCode = 0x00; // type has to be 0x00 for node status
		int result = writeQuestionSectionWireFormat( dst, dstIndex );
		questionName.hexCode = tmp;
		return result;
	}
	int readBodyWireFormat( byte[] src, int srcIndex ) {
		return 0;
	}
	int writeRDataWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readRDataWireFormat( byte[] src, int srcIndex ) {
		return 0;
	}
	public String toString() {
		return new String( "NodeStatusRequest[" +
			super.toString() + "]" );
	}
}
jcifs_0.8.2/src/jcifs/netbios/Lmhosts.java100644      0      0       10744 10025170725  15701 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import jcifs.Config;
import jcifs.smb.SmbFileInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Hashtable;
import java.net.UnknownHostException;

public class Lmhosts {

	static String filename = Config.getProperty( "jcifs.netbios.lmhosts" );
	static Hashtable tab = new Hashtable();
	static long lastModified = 1L;
	static int alt;

	/**
	 * This is really just for {@link jcifs.UniAddress}. It does
	 * not throw an {@link java.net.UnknownHostException} because this
	 * is queried frequently and exceptions would be rather costly to
	 * throw on a regular basis here.
	 */

	public synchronized static NbtAddress getByName( String host ) {
		return getByName( new Name( host, 0x20, null ));
	}

	synchronized static NbtAddress getByName( Name name ) {
		NbtAddress result = null;

		try {
			if( filename != null ) {
				File f = new File( filename );
				long lm;

				if(( lm = f.lastModified() ) > lastModified ) {
					lastModified = lm;
					tab.clear();
					alt = 0;
					populate( new FileReader( f ));
				}
				result = (NbtAddress)tab.get( name );
			}
		} catch( FileNotFoundException fnfe ) {
			Log.println( Log.WARNINGS, "netbios name service exception",
									"lmhosts file not found: " + filename );
		} catch( IOException ioe ) {
			Log.printStackTrace( "netbios name service exception", ioe );
		}
		return result;
	}

	static void populate( Reader r ) throws IOException {
		String line;
		BufferedReader br = new BufferedReader( r );

		while(( line = br.readLine() ) != null ) {
			line = line.toUpperCase().trim();
			if( line.length() == 0 ) {
				continue;
			} else if( line.charAt( 0 ) == '#' ) {
				if( line.startsWith( "#INCLUDE " )) {
					line = line.substring( line.indexOf( '\\' ));
					String url = "smb:" + line.replace( '\\', '/' );

					if( alt > 0 ) {
						try {
							populate( new InputStreamReader( new SmbFileInputStream( url )));
						} catch( IOException ioe ) {
							Log.println( Log.WARNINGS, "netbios name service warning",
										"failed to load lmhosts alternate include: " + url );
							continue;
						}

						/* An include was loaded successfully. We can skip
						 * all other includes up to the #END_ALTERNATE tag.
						 */

						alt--;
						while(( line = br.readLine() ) != null ) {
							line = line.toUpperCase().trim();
							if( line.startsWith( "#END_ALTERNATE" )) {
								break;
							}
						}
					} else {
						populate( new InputStreamReader( new SmbFileInputStream( url )));
					}
				} else if( line.startsWith( "#BEGIN_ALTERNATE" )) {
					alt++;
				} else if( line.startsWith( "#END_ALTERNATE" ) && alt > 0 ) {
					alt--;
					throw new IOException( "no lmhosts alternate includes loaded" );
				}
			} else if( Character.isDigit( line.charAt( 0 ))) {
				char[] data = line.toCharArray();
				int ip, i, j;
				Name name;
				NbtAddress addr;
				char c;

				c = '.';
				ip = i = 0;
				for( ; i < data.length && c == '.'; i++ ) {
					int b = 0x00;

					for( ; i < data.length && ( c = data[i] ) >= 48 && c <= 57; i++ ) {
						b = b * 10 + c - '0';
					}
					ip = ( ip << 8 ) + b;
				}
				while( i < data.length && Character.isWhitespace( data[i] )) {
					i++;
				}
				j = i;
				while( j < data.length && Character.isWhitespace( data[j] ) == false ) {
					j++;
				}

				name = new Name( line.substring( i, j ), 0x20, null );
				addr = new NbtAddress( name, ip, false, NbtAddress.B_NODE,
									false, false, true, true,
									NbtAddress.unknownMacAddress );
				tab.put( name, addr );
			}
		}
	}
}
jcifs_0.8.2/src/jcifs/netbios/NbtSocket.java100644      0      0       10244 10025170725  16137 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.net.Socket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import jcifs.Config;

/**
 * This class represents a netbios TCP/IP socket. Under no
 * conditions will users of jcifs need not be concerned with this class as
 * netbios services are handled internally to the smb package. It is
 * only public so the smb package can access it.
 */

public class NbtSocket extends Socket {

	private static final int SSN_SRVC_PORT = 139;
	private static final int BUFFER_SIZE = 512;
    private static final int DEFAULT_SO_TIMEOUT = 5000;

	NbtAddress address;
	Name calledName;
	int soTimeout;

	public NbtSocket() {
		super();
	}
	public NbtSocket( NbtAddress address, int port ) throws IOException {
		this( address, port, null, 0 );
	}
	public NbtSocket( NbtAddress address, int port,
								InetAddress localAddr, int localPort ) throws IOException {
		this( address, null, port, localAddr, localPort );
	}
	public NbtSocket( NbtAddress address, String calledName, int port,
								InetAddress localAddr, int localPort ) throws IOException {
		super( address.getInetAddress(), ( port == 0 ? SSN_SRVC_PORT : port ),
								localAddr, localPort );
		this.address = address;
		if( calledName == null ) {
			this.calledName = address.hostName;
		} else {
			this.calledName = new Name( calledName, 0x20, null );
		}
        soTimeout = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
		connect();
	}

	public NbtAddress getNbtAddress() {
		return address;
	}
	InputStream getRawInputStream() throws IOException {
		return super.getInputStream();
	}
	OutputStream getRawOutputStream() throws IOException {
		return super.getOutputStream();
	}
	public InputStream getInputStream() throws IOException {
		return new SocketInputStream( super.getInputStream() );
	}
	public OutputStream getOutputStream() throws IOException {
		return new SocketOutputStream( super.getOutputStream() );
	}
	public int getPort() {
		return super.getPort();
	}
	public InetAddress getLocalAddress() {
		return super.getLocalAddress();
	}
	public int getLocalPort() {
		return super.getLocalPort();
	}
	public String toString() {
		return "NbtSocket[addr=" + address +
				",port=" + super.getPort() +
				",localport=" + super.getLocalPort() + "]";
	}
	private void connect() throws IOException {
		byte[] buffer = new byte[BUFFER_SIZE];

		InputStream in = super.getInputStream();
		OutputStream out = super.getOutputStream();

		SessionServicePacket ssp0 = new SessionRequestPacket( calledName, NbtAddress.localhost.hostName );
		out.write( buffer, 0, ssp0.writeWireFormat( buffer, 0 ));

		setSoTimeout( soTimeout );
		switch( ssp0.readPacketType( in, buffer, 0 )) {
			case SessionServicePacket.POSITIVE_SESSION_RESPONSE:
				Log.println( Log.WARNINGS, "session service warning", " session established ok with " + address );
				return;
			case SessionServicePacket.NEGATIVE_SESSION_RESPONSE:
				int errorCode = (int)( in.read() & 0xFF );
				throw new NbtException( NbtException.ERR_SSN_SRVC, errorCode );
			case -1:
				throw new NbtException( NbtException.ERR_SSN_SRVC, NbtException.CONNECTION_REFUSED );
			default:
				throw new NbtException( NbtException.ERR_SSN_SRVC, 0 );
		}
	}
	public void close() throws IOException {
		Log.println( Log.WARNINGS, "netbios socket closed", this );
		super.close();
	}
}
jcifs_0.8.2/src/jcifs/netbios/NameServicePacket.java100644      0      0       24044 10025170725  17577 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.net.InetAddress;

abstract class NameServicePacket {

	// opcode
	static final int QUERY = 0;
	static final int WACK = 7;

	// rcode
	static final int FMT_ERR = 0x1;
	static final int SRV_ERR = 0x2;
	static final int IMP_ERR = 0x4;
	static final int RFS_ERR = 0x5;
	static final int ACT_ERR = 0x6;
	static final int CFT_ERR = 0x7;

	// type/class
	static final int NB_IN     = 0x00200001;
	static final int NBSTAT_IN = 0x00210001;
	static final int NB        = 0x0020;
	static final int NBSTAT    = 0x0021;
	static final int IN        = 0x0001;
	static final int A         = 0x0001;
	static final int NS        = 0x0002;
	static final int NULL      = 0x000a;

	static final int HEADER_LENGTH = 12;

	// header field offsets
	static final int OPCODE_OFFSET = 2;
	static final int QUESTION_OFFSET = 4;
	static final int ANSWER_OFFSET = 6;
	static final int AUTHORITY_OFFSET = 8;
	static final int ADDITIONAL_OFFSET = 10;

	static final int LOOKUP_RESP_LIMIT = jcifs.Config.getInt( "jcifs.netbios.lookupRespLimit", 5 );

	static int addrIndex = 0;

	static void writeInt2( int val, byte[] dst, int dstIndex ) {
		dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
		dst[dstIndex] = (byte)( val & 0xFF );
	}
	static void writeInt4( int val, byte[] dst, int dstIndex ) {
		dst[dstIndex++] = (byte)(( val >> 24 ) & 0xFF );
		dst[dstIndex++] = (byte)(( val >> 16 ) & 0xFF );
		dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
		dst[dstIndex] = (byte)( val & 0xFF );
	}
	static int readInt2( byte[] src, int srcIndex ) {
		return (( src[srcIndex] & 0xFF ) << 8 ) +
				( src[srcIndex + 1] & 0xFF );
	}
	static int readInt4( byte[] src, int srcIndex ) {
		return (( src[srcIndex] & 0xFF ) << 24 ) +
				(( src[srcIndex + 1] & 0xFF ) << 16 ) +
				(( src[srcIndex + 2] & 0xFF ) << 8 ) +
				( src[srcIndex + 3] & 0xFF );
	}

	static int readNameTrnId( byte[] src, int srcIndex ) {
		return readInt2( src, srcIndex );
	}

	int nameTrnId;

	int opCode,
			resultCode,
			questionCount,
			answerCount,
			authorityCount,
			additionalCount;
	boolean received,
			isResponse,
			isAuthAnswer,
			isTruncated,
			isRecurDesired,
			isRecurAvailable,
			isBroadcast;

	Name questionName;
	Name recordName;

	int questionType,
			questionClass,
			recordType,
			recordClass,
			ttl,
			rDataLength;

	InetAddress addr;

	NameServicePacket() {
		isRecurDesired = true;
		isBroadcast = true;
		questionCount = 1;
		questionClass = IN;
	}

	int writeWireFormat( byte[] dst, int dstIndex ) {
		int start = dstIndex;
		dstIndex += writeHeaderWireFormat( dst, dstIndex );
		dstIndex += writeBodyWireFormat( dst, dstIndex );
		return dstIndex - start;
	}
	int readWireFormat( byte[] src, int srcIndex ) {
		int start = srcIndex;
		srcIndex += readHeaderWireFormat( src, srcIndex );
		srcIndex += readBodyWireFormat( src, srcIndex );
		return srcIndex - start;
	}

	int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
		int start = dstIndex;
		writeInt2( nameTrnId, dst, dstIndex );
		dst[dstIndex + OPCODE_OFFSET] = (byte)(( isResponse ? 0x80 : 0x00 ) +
						(( opCode << 3 ) & 0x78 ) +
						( isAuthAnswer ? 0x04 : 0x00 ) +
						( isTruncated ? 0x02 : 0x00 ) +
						( isRecurDesired ? 0x01 : 0x00 ));
		dst[dstIndex + OPCODE_OFFSET + 1] = (byte)(( isRecurAvailable ? 0x80 : 0x00 ) +
						( isBroadcast ? 0x10 : 0x00 ) +
						( resultCode & 0x0F ));
		writeInt2( questionCount, dst, start + QUESTION_OFFSET );
		writeInt2( answerCount, dst, start + ANSWER_OFFSET );
		writeInt2( authorityCount, dst, start + AUTHORITY_OFFSET );
		writeInt2( additionalCount, dst, start + ADDITIONAL_OFFSET );
		return HEADER_LENGTH;
	}
	int readHeaderWireFormat( byte[] src, int srcIndex ) {
		nameTrnId       = readInt2( src, srcIndex );
        isResponse      = (( src[srcIndex + OPCODE_OFFSET] & 0x80 ) == 0 ) ? false : true;
		opCode          = ( src[srcIndex + OPCODE_OFFSET] & 0x78 ) >> 3;
		isAuthAnswer    = (( src[srcIndex + OPCODE_OFFSET] & 0x04 ) == 0 ) ? false : true;
		isTruncated     = (( src[srcIndex + OPCODE_OFFSET] & 0x02 ) == 0 ) ? false : true;
        isRecurDesired  = (( src[srcIndex + OPCODE_OFFSET] & 0x01 ) == 0 ) ? false : true;
        isRecurAvailable =
						(( src[srcIndex + OPCODE_OFFSET + 1] & 0x80 ) == 0 ) ? false : true;
        isBroadcast     = (( src[srcIndex + OPCODE_OFFSET + 1] & 0x10 ) == 0 ) ? false : true;
        resultCode      = src[srcIndex + OPCODE_OFFSET + 1] & 0x0F;
		questionCount   = readInt2( src, srcIndex + QUESTION_OFFSET );
		answerCount     = readInt2( src, srcIndex + ANSWER_OFFSET );
		authorityCount  = readInt2( src, srcIndex + AUTHORITY_OFFSET );
		additionalCount = readInt2( src, srcIndex + ADDITIONAL_OFFSET );
		return HEADER_LENGTH;
	}
	int writeQuestionSectionWireFormat( byte[] dst, int dstIndex ) {
		int start = dstIndex;
		dstIndex += questionName.writeWireFormat( dst, dstIndex );
		writeInt2( questionType, dst, dstIndex );
		dstIndex += 2;
		writeInt2( questionClass, dst, dstIndex );
		dstIndex += 2;
		return dstIndex - start;
	}
	int readQuestionSectionWireFormat( byte[] src, int srcIndex ) {
		int start = srcIndex;
		srcIndex += questionName.readWireFormat( src, srcIndex );
		questionType = readInt2( src, srcIndex );
		srcIndex += 2;
		questionClass = readInt2( src, srcIndex );
		srcIndex += 2;
		return srcIndex - start;
	}
	int writeResourceRecordWireFormat( byte[] dst, int dstIndex ) {
		int start = dstIndex;
		if( recordName == questionName ) {
			dst[dstIndex++] = (byte)0xC0; // label string pointer to
			dst[dstIndex++] = (byte)0x0C; // questionName (offset 12)
		} else {
			dstIndex += recordName.writeWireFormat( dst, dstIndex );
		}
		writeInt2( recordType, dst, dstIndex );
		dstIndex += 2;
		writeInt2( recordClass, dst, dstIndex );
		dstIndex += 2;
		writeInt4( ttl, dst, dstIndex );
		dstIndex += 4;
		rDataLength = writeRDataWireFormat( dst, dstIndex + 2 );
		writeInt2( rDataLength, dst, dstIndex );
		dstIndex += 2 + rDataLength;
		return dstIndex - start;
	}
	int readResourceRecordWireFormat( byte[] src, int srcIndex ) {
		int start = srcIndex;
		int end;

		if(( src[srcIndex] & 0xC0 ) == 0xC0 ) {
			recordName = questionName; // label string pointer to questionName
			srcIndex += 2;
		} else {
			srcIndex += recordName.readWireFormat( src, srcIndex );
		}
		recordType = readInt2( src, srcIndex );
		srcIndex += 2;
		recordClass = readInt2( src, srcIndex );
		srcIndex += 2;
		ttl = readInt4( src, srcIndex );
		srcIndex += 4;
		rDataLength = readInt2( src, srcIndex );
		srcIndex += 2;

		end = srcIndex + rDataLength;
		for( int i = 0; srcIndex < end; i++ ) {
			srcIndex += readRDataWireFormat( src, srcIndex );
			if( i == addrIndex ) {
				addrIndex++;
				if( addrIndex == LOOKUP_RESP_LIMIT ) {
					addrIndex = 0;
				}
				return end - start;
			}
		}
		addrIndex = 0;

		return srcIndex - start;
	}

	abstract int writeBodyWireFormat( byte[] dst, int dstIndex );
	abstract int readBodyWireFormat( byte[] src, int srcIndex );
	abstract int writeRDataWireFormat( byte[] dst, int dstIndex );
	abstract int readRDataWireFormat( byte[] src, int srcIndex );

	public String toString() {
		String opCodeString,
				resultCodeString,
				questionTypeString,
				questionClassString,
				recordTypeString,
				recordClassString;

		switch( opCode ) {
			case QUERY:
				opCodeString = "QUERY";
				break;
			case WACK:
				opCodeString = "WACK";
				break;
			default:
				opCodeString = Integer.toString( opCode );
		}
		switch( resultCode ) {
			case FMT_ERR:
				resultCodeString = "FMT_ERR";
				break;
			case SRV_ERR:
				resultCodeString = "SRV_ERR";
				break;
			case IMP_ERR:
				resultCodeString = "IMP_ERR";
				break;
			case RFS_ERR:
				resultCodeString = "RFS_ERR";
				break;
			case ACT_ERR:
				resultCodeString = "ACT_ERR";
				break;
			case CFT_ERR:
				resultCodeString = "CFT_ERR";
				break;
			default:
				resultCodeString = "0x" + Log.getHexString( resultCode, 1 );
		}
		switch( questionType ) {
			case NB:
				questionTypeString = "NB";
			case NBSTAT:
				questionTypeString = "NBSTAT";
			default:
				questionTypeString = "0x" + Log.getHexString( questionType, 4 );
		}
		switch( recordType ) {
			case A:
				recordTypeString = "A";
				break;
			case NS:
				recordTypeString = "NS";
				break;
			case NULL:
				recordTypeString = "NULL";
				break;
			case NB:
				recordTypeString = "NB";
			case NBSTAT:
				recordTypeString = "NBSTAT";
			default:
				recordTypeString = "0x" + Log.getHexString( recordType, 4 );
		}

		return new String(
				"nameTrnId=" + nameTrnId +
				",isResponse=" + isResponse +
				",opCode=" + opCodeString +
				",isAuthAnswer=" + isAuthAnswer +
				",isTruncated=" + isTruncated +
				",isRecurAvailable=" + isRecurAvailable +
				",isRecurDesired=" + isRecurDesired +
				",isBroadcast=" + isBroadcast +
				",resultCode=" + resultCode +
				",questionCount=" + questionCount +
				",answerCount=" + answerCount +
				",authorityCount=" + authorityCount +
				",additionalCount=" + additionalCount +
				",questionName=" + questionName +
				",questionType=" + questionTypeString +
				",questionClass=" + ( questionClass == IN ? "IN" :
							"0x" + Log.getHexString( questionClass, 4 )) +
				",recordName=" + recordName +
				",recordType=" + recordTypeString +
				",recordClass=" + ( recordClass == IN ? "IN" :
							"0x" + Log.getHexString( recordClass, 4 )) +
				",ttl=" + ttl +
				",rDataLength=" + rDataLength );
	}
}

jcifs_0.8.2/src/jcifs/netbios/NameServiceClient.java100644      0      0       27332 10025170725  17611 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.netbios;

import java.net.InetAddress;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Hashtable;
import java.util.StringTokenizer;
import jcifs.Config;

class NameServiceClient implements Runnable {

    static final int DEFAULT_SO_TIMEOUT = 5000;
    static final int DEFAULT_RCV_BUF_SIZE = 576;
    static final int DEFAULT_SND_BUF_SIZE = 576;
	static final int NAME_SERVICE_UDP_PORT = 137;
	static final int DEFAULT_RETRY_COUNT = 2;
	static final int DEFAULT_RETRY_TIMEOUT = 3000;

	static final int RESOLVER_LMHOSTS = 1;
	static final int RESOLVER_BCAST   = 2;
	static final int RESOLVER_WINS    = 3;

    InetAddress laddr, baddr, nbns;
    int port, soTimeout, retryCount, retryTimeout, closeTimeout;
    int snd_buf_size, rcv_buf_size;
    byte[] snd_buf, rcv_buf;
    DatagramSocket socket;
    DatagramPacket in, out;
	Hashtable responseTable;
    Thread thread;
	int nextNameTrnId;
	Object socketLock;
	int[] resolveOrder;

	NameServiceClient() {
		this( Config.getInt( "jcifs.netbios.lport", 0 ),
			Config.getInetAddress( "jcifs.netbios.laddr", null ));
	}
    NameServiceClient( int port, InetAddress laddr ) {
        this.port = port;
        this.laddr = laddr;

		try {
			baddr = Config.getInetAddress( "jcifs.netbios.baddr",
						InetAddress.getByName( "255.255.255.255" ));
		} catch( UnknownHostException uhe ) {
		}

		nbns = Config.getInetAddress( "jcifs.netbios.wins", null );
        soTimeout = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
		retryCount = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT );
		retryTimeout = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT);
        rcv_buf_size = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
        snd_buf_size = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE );
        rcv_buf = new byte[rcv_buf_size];
        snd_buf = new byte[snd_buf_size];
        in  = new DatagramPacket( rcv_buf, rcv_buf_size );
        out = new DatagramPacket( snd_buf, snd_buf_size, baddr, NAME_SERVICE_UDP_PORT );
		responseTable = new Hashtable();
		nextNameTrnId = 0;
		socketLock = new Object();

		String ro = Config.getProperty( "jcifs.resolveOrder" );
		if( ro == null || ro.length() == 0 ) {

			/* No resolveOrder has been specified, use the
			 * default which is LMHOSTS,WINS,BCAST,DNS or just
			 * LMHOSTS,BCAST,DNS if jcifs.netbios.wins has not
			 * been specified.
			 */

			if( nbns == null ) {
				resolveOrder = new int[2];
				resolveOrder[0] = RESOLVER_LMHOSTS;
				resolveOrder[1] = RESOLVER_BCAST;
			} else {
				resolveOrder = new int[3];
				resolveOrder[0] = RESOLVER_LMHOSTS;
				resolveOrder[1] = RESOLVER_WINS;
				resolveOrder[2] = RESOLVER_BCAST;
			}
		} else {
			int[] tmp = new int[3];
			StringTokenizer st = new StringTokenizer( ro, "," );
			int i = 0;
			while( st.hasMoreTokens() ) {
				String s = st.nextToken().trim();
				if( s.equalsIgnoreCase( "LMHOSTS" )) {
					tmp[i++] = RESOLVER_LMHOSTS;
				} else if( s.equalsIgnoreCase( "WINS" )) {
					if( nbns == null ) {
						Log.println( Log.WARNINGS, "netbios name service warning",
								" resolveOrder specifies WINS however the " +
								"jcifs.netbios.wins property has not been set" );
						continue;
					}
					tmp[i++] = RESOLVER_WINS;
				} else if( s.equalsIgnoreCase( "BCAST" )) {
					tmp[i++] = RESOLVER_BCAST;
				} else if( s.equalsIgnoreCase( "DNS" )) {
					; // skip
				} else {
					Log.println( Log.WARNINGS, "netbios name service warning",
								"unknown resolver method: " + s );
				}
			}
			resolveOrder = new int[i];
			System.arraycopy( tmp, 0, resolveOrder, 0, i );
		}
    }

	int getNextNameTrnId() {
		if(( ++nextNameTrnId & 0xFFFF ) == 0 ) {
			nextNameTrnId = 1;
		}
		return nextNameTrnId;
	}
    void ensureOpen( int timeout ) throws IOException {
		closeTimeout = 0;
		if( soTimeout != 0 ) {
			closeTimeout = Math.max( soTimeout, timeout );
		}
		// If socket is still good, the new closeTimeout will
		// be ignored; see tryClose comment.
        if( socket == null ) {
        	socket = new DatagramSocket( port, laddr );
        	thread = new Thread( this, "JCIFS-NameServiceClient" );
			thread.setDaemon( true );
        	thread.start();
		}
    }
    void tryClose() {
		synchronized( socketLock ) {

			/* Yes, there is the potential to drop packets
			 * because we might close the socket during a
			 * request. However the chances are slim and the
			 * retry code should ensure the overall request
			 * is serviced. The alternative complicates things
			 * more than I think is worth it.
			 */

        	if( socket != null ) {
        	   	socket.close();
        		socket = null;
        	}
        	thread = null;
			responseTable.clear();
		}
    }
    public void run() {
		int nameTrnId;
		NameServicePacket response;

        while( thread == Thread.currentThread() ) {
			in.setLength( rcv_buf_size );
        	try {
        		socket.setSoTimeout( closeTimeout );
            	socket.receive( in );
        	} catch( IOException ioe ) {
				tryClose();
				break;
        	}

			Log.println( Log.DEBUGGING, "nbt name service debugging",
												" new data read from socket" );

			nameTrnId = NameServicePacket.readNameTrnId( rcv_buf, 0 );
			response = (NameServicePacket)responseTable.get( new Integer( nameTrnId ));
			if( response == null || response.received ) {
				continue;
			}
			synchronized( response ) {
				response.readWireFormat( rcv_buf, 0 );
				response.received = true;

				Log.printPacketData( "nbt name service packet receviced", response );
				Log.printHexDump( "datagram packet received from: " +
						in.getAddress().getHostAddress(), rcv_buf, 0, in.getLength() );

				response.notify();
			}
        }
    }
    void send( NameServicePacket request, NameServicePacket response,
											int timeout ) throws IOException {
		Integer nid = null;

		synchronized( response ) {
			try {
				synchronized( socketLock ) {
					request.nameTrnId = getNextNameTrnId();
					nid = new Integer( request.nameTrnId );

		        	out.setAddress( request.addr );
		        	out.setLength( request.writeWireFormat( snd_buf, 0 ));
					response.received = false;

					responseTable.put( nid, response );
		        	ensureOpen( timeout + 1000 );
		            socket.send( out );

					Log.printPacketData( "nbt name service packet sent", request );
					Log.printHexDump( "datagram packet sent to: " +
								out.getAddress().getHostAddress(), snd_buf, 0, out.getLength() );
				}

				response.wait( timeout );

			} catch( InterruptedException ie ) {
			} finally {
				responseTable.remove( nid );
			}
		}
    }

	NbtAddress getByName( Name name, InetAddress addr )
											throws UnknownHostException {
		int n;
		NameQueryRequest request = new NameQueryRequest( name );
		NameQueryResponse response = new NameQueryResponse();

		if( addr != null ) { /* UniAddress calls always use this
							  * because it specifies addr
							  */
			request.addr = addr; /* if addr ends with 255 flag it bcast */
			request.isBroadcast = (addr.getAddress()[3] == (byte)0xFF);

			n = retryCount;
			do {
				try {
					send( request, response, retryTimeout );
				} catch( IOException ioe ) {
					Log.printStackTrace( "nbt name service send:", ioe );
					throw new UnknownHostException( ioe.getMessage() );
				}

				if( response.received && response.resultCode == 0 ) {
					response.addrEntry.hostName.srcHashCode = addr.hashCode();
					return response.addrEntry;
				}
			} while( --n > 0 && request.isBroadcast );

			throw new UnknownHostException( name.toString() );
		}

		/* If a target address to query was not specified explicitly
		 * with the addr parameter we fall into this resolveOrder routine.
		 */

		for( int i = 0; i < resolveOrder.length; i++ ) {
			try {
				switch( resolveOrder[i] ) {
					case RESOLVER_LMHOSTS:
						NbtAddress ans = Lmhosts.getByName( name );
						if( ans != null ) {
							ans.hostName.srcHashCode = 0; // just has to be different
														  // from other methods
							return ans;
						}
						break;
					case RESOLVER_WINS:
					case RESOLVER_BCAST:
						if( resolveOrder[i] == RESOLVER_WINS &&
								name.name != NbtAddress.MASTER_BROWSER_NAME &&
								name.hexCode != 0x1d ) {
							request.addr = nbns;
							request.isBroadcast = false;
						} else {
							request.addr = baddr;
							request.isBroadcast = true;
						}

						n = retryCount;
						while( n-- > 0 ) {
							try {
								send( request, response, retryTimeout );
							} catch( IOException ioe ) {
								Log.printStackTrace( "nbt name service send:", ioe );
								throw new UnknownHostException( ioe.getMessage() );
							}
							if( response.received && response.resultCode == 0 ) {

/* Before we return, in anticipation of this address being cached we must
 * augment the addresses name's hashCode to distinguish those resolved by
 * Lmhosts, WINS, or BCAST. Otherwise a failed query from say WINS would
 * get pulled out of the cache for a BCAST on the same name.
 */
								response.addrEntry.hostName.srcHashCode =
														request.addr.hashCode();
								return response.addrEntry;
							} else if( resolveOrder[i] == RESOLVER_WINS ) {
								/* If WINS reports negative, no point in retry
								 */
								break;
							}
						}
						break;
				}
			} catch( IOException ioe ) {
			}
		}
		throw new UnknownHostException( name.name );
	}
	NbtAddress[] getNodeStatus( NbtAddress addr ) throws UnknownHostException {
		int n, srcHashCode;
		NodeStatusRequest request;
		NodeStatusResponse response;

		response = new NodeStatusResponse( addr );
		request = new NodeStatusRequest(
							new Name( NbtAddress.ANY_HOSTS_NAME, 0x00, null));
		request.addr = addr.getInetAddress();

		n = retryCount;
		while( n-- > 0 ) {
			try {
				send( request, response, retryTimeout );
			} catch( IOException ioe ) {
				Log.printStackTrace( "nbt name service send:", ioe );
				throw new UnknownHostException( ioe.getMessage() );
			}
			if( response.received && response.resultCode == 0 ) {

		/* For name queries resolved by different sources (e.g. WINS,
		 * BCAST, Node Status) we need to augment the hashcode generated
		 * for the addresses hostname or failed lookups for one type will
		 * be cached and cause other types to fail even though they may
		 * not be the authority for the name. For example, if a WINS lookup
		 * for FOO fails and caches unknownAddress for FOO, a subsequent
		 * lookup for FOO using BCAST should not fail because of that
		 * name cached from WINS.
		 *
		 * So, here we apply the source addresses hashCode to each name to
		 * make them specific to who resolved the name.
		 */

				srcHashCode = request.addr.hashCode();
				for( int i = 0; i < response.addressArray.length; i++ ) {
					response.addressArray[i].hostName.srcHashCode = srcHashCode;
				}
				return response.addressArray;
			}
		}
		throw new UnknownHostException( addr.hostName.name );
	}
}
jcifs_0.8.2/src/jcifs/smb/SmbSession.java100644      0      0       13313 10025170724  15445 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.smb;

import java.util.Vector;
import java.util.Enumeration;
import java.net.InetAddress;
import java.net.UnknownHostException;
import jcifs.UniAddress;

/**
 * The class represents a user's session established with an SMB/CIFS
 * server. This class is used internally to the jCIFS library however
 * applications may wish to authenticate aribrary user credentials
 * with the <tt>logon</tt> method. It is noteworthy that jCIFS does not
 * support DCE/RPC at this time and therefore does not use the NETLOGON
 * procedure. Instead, it simply performs a "tree connect" to IPC$ using
 * the supplied credentials. This is only a subset of the NETLOGON procedure
 * but is achives the same effect.
 */

public final class SmbSession {

	public static byte[] getChallenge( UniAddress dc ) throws SmbException, UnknownHostException {
		SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
		trans.negotiate();
		return trans.server.encryptionKey;
	}
/**
 * Authenticate arbitrary credentials represented by the
 * <tt>NtlmPasswordAuthentication</tt> object against the domain controller
 * specified by the <tt>UniAddress</tt> parameter. If the credentials are
 * not accepted, an <tt>SmbAuthException</tt> will be thrown. If an error
 * occurs an <tt>SmbException</tt> will be thrown. If the credentials are
 * valid, the method will return without throwing an exception. See the
 * last <a href="../../../../FAQ.html">FAQ</a> question.
 */
	public static void logon( UniAddress dc,
						NtlmPasswordAuthentication auth ) throws SmbException {
		SmbTransport.getSmbTransport( dc, 0 ).getSmbSession( auth ).getSmbTree( "IPC$", null ).treeConnect( null, null );
	}

	int uid;
	NtlmPasswordAuthentication auth;
	SmbTransport transport;
	Vector trees;
	boolean sessionSetup;

	SmbSession( SmbTransport transport, NtlmPasswordAuthentication auth ) {
		this.transport = transport;
		this.auth = auth;
		trees = new Vector();
	}

	synchronized SmbTree getSmbTree( String share, 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;
	}
	boolean matches( NtlmPasswordAuthentication auth ) {
		return this.auth == auth || this.auth.equals( auth );
	}
	void sendTransaction( SmbComTransaction request,
							SmbComTransactionResponse response ) throws SmbException {
		// transactions are not batchable
		sessionSetup( null, null );
		request.uid = uid;
		request.auth = auth;
		transport.sendTransaction( request, response );
	}
	void send( ServerMessageBlock request,
							ServerMessageBlock response ) throws SmbException {
		if( response != null ) {
			response.received = false;
		}
		sessionSetup( request, response );
		if( response != null && response.received ) {
			return;
		}
		request.uid = uid;
		request.auth = auth;
		transport.send( request, response );
	}
	void sessionSetup( ServerMessageBlock andx,
							ServerMessageBlock andxResponse ) throws SmbException {
synchronized( transport ) {
		if( sessionSetup ) {
			return;
		}

		transport.negotiate();

		if( transport.useSigning && transport.macSigningKey == null &&
				NtlmPasswordAuthentication.NULL != auth &&
				NtlmPasswordAuthentication.NULL.equals( auth ) == false ) {
			//	NtlmPasswordAuthentication.GUEST.equals( auth ) == false ) {
                    /* The first SMB_COM_SESSION_SETUP_ANX with creds other than
                     * null or guest generates the signing key */
			transport.initSigning( auth );
		}

		Log.println( Log.WARNINGS, "smb session setup warning",
					" requesting session with accountName=" + auth.username +
					",primaryDomain=" + auth.domain );

		/*
		 * Session Setup And X Request / Response
		 */

		SmbComSessionSetupAndX request = new SmbComSessionSetupAndX( this, andx );
		SmbComSessionSetupAndXResponse response = new SmbComSessionSetupAndXResponse( andxResponse );
		request.auth = auth;
		transport.send( request, response );

		uid = response.uid;
		sessionSetup = true;
}
	}
	void logoff( boolean inError ) {
synchronized( transport ) {
		if( sessionSetup == false ) {
			return;
		}

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

		if( transport.server.security == ServerMessageBlock.SECURITY_SHARE ) {
			return;
		}

		if( !inError ) {

			/*
			 * Logoff And X Request / Response
			 */

			try {
				SmbComLogoffAndX request = new SmbComLogoffAndX( null );
				request.uid = uid;
				transport.send( request, null );
			} catch( SmbException se ) {
			}
		}
		sessionSetup = false;
}
	}
	public String toString() {
		return "SmbSession[accountName=" + auth.username +
				",primaryDomain=" + auth.domain +
				",uid=" + uid +
				",sessionSetup=" + sessionSetup + "]";
	}
}
jcifs_0.8.2/src/jcifs/smb/Trans2FindFirst2Response.java100644      0      0       17136 10025170724  20152 0ustar     0      0 /* jcifs smb client library in Java
 * Copyright (C) 2000  "Michael B. Allen" <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 jcifs.smb;

import java.io.UnsupportedEncodingException;
import java.util.Date;

class Trans2FindFirst2Response extends SmbComTransactionResponse {

	// information levels

	static final int SMB_INFO_STANDARD                 = 1;
	static final int SMB_INFO_QUERY_EA_SIZE            = 2;
	static final int SMB_INFO_QUERY_EAS_FROM_LIST      = 3;
	static final int SMB_FIND_FILE_DIRECTORY_INFO      = 0x101;
	static final int SMB_FIND_FILE_FULL_DIRECTORY_INFO = 0x102;
	static final int SMB_FILE_NAMES_INFO               = 0x103;
	static final int SMB_FILE_BOTH_DIRECTORY_INFO      = 0x104;

	class SmbFindFileBothDirectoryInfo implements FileEntry {
		int nextEntryOffset;
		int fileIndex;
		long creationTime;
		long lastAccessTime;
		long lastWriteTime;
		long changeTime;
		long endOfFile;
		long allocationSize;
		int extFileAttributes;
		int fileNameLength;
		int eaSize;
		int shortNameLength;
		String shortName;
		String filename;

		public String getName() {
			return filename;
		}
		public int getType() {
			return SmbFile.TYPE_FILESYSTEM;
		}
		public int getAttributes() {
			return extFileAttributes;
		}
		public long createTime() {
			return creationTime;
		}
		public long lastModified() {
			return lastWriteTime;
		}
		public long length() {
			return endOfFile;
		}

		public String toString() {
			return new String( "SmbFindFileBothDirectoryInfo[" +
				"nextEntryOffset=" + nextEntryOffset +
				",fileIndex=" + fileIndex +
				",creationTime=" + new Date( creationTime ) +
				",lastAccessTime=" + new Date( lastAccessTime ) +
				",lastWriteTime=" + new Date( lastWriteTime ) +
				",changeTime=" + new Date( changeTime ) +
				",endOfFile=" + endOfFile +
				",allocationSize=" + allocationSize +
				",extFileAttributes=" + extFileAttributes +
				",fileNameLength=" + fileNameLength +
				",eaSize=" + eaSize +
				",shortNameLength=" + shortNameLength +
				",shortName=" + shortName +
				",filename=" + filename + "]" );
		}
	}

	int sid;
	boolean isEndOfSearch;
	int eaErrorOffset;
	int lastNameOffset, lastNameBufferIndex;
	String lastName;
	int resumeKey;


	Trans2FindFirst2Response() {
		command = SMB_COM_TRANSACTION2;
		subCommand = SmbComTransaction.TRANS2_FIND_FIRST2;
	}

	String readString( byte[] src, int srcIndex, int len ) {
		String str = null;
		try {
			if( useUnicode ) {
				// should Unicode alignment be corrected for here?
				str = new String( src, srcIndex, len, "UnicodeLittle" );
			} else {
	
				/* On NT without Unicode the fileNameLength
				 * includes the '\0' whereas on win98 it doesn't. I
				 * guess most clients only support non-unicode so
				 * they don't run into this.
				 */
	
	/* UPDATE: Maybe not! Could this be a Unicode alignment issue. I hope
	 * so. We cannot just comment out this method and use readString of
	 * ServerMessageBlock.java because the arguments are different, however
	 * one might be able to reduce this.
	 */
	
				if( len > 0 && src[srcIndex + len - 1] == '\0' ) {
					len--;
				}
				str = new String( src, srcIndex, len, ServerMessageBlock.encoding );
			}
		} catch( UnsupportedEncodingException uee ) {
			Log.printStackTrace( "smb exception", uee );
		}
		return str;
	}
	int writeSetupWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int writeParametersWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int writeDataWireFormat( byte[] dst, int dstIndex ) {
		return 0;
	}
	int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
		return 0;
	}
	int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
		int start = bufferIndex;

		if( subCommand == SmbComTransaction.TRANS2_FIND_FIRST2 ) {
			sid = readInt2( buffer, bufferIndex );
			bufferIndex += 2;
		}
		numEntries = readInt2( buffer, bufferIndex );
		bufferIndex += 2;
		isEndOfSearch = ( buffer[bufferIndex] & 0x01 ) == 0x01 ? true : false;
		bufferIndex += 2;
		eaErrorOffset = readInt2( buffer, bufferIndex );
		bufferIndex += 2;
		lastNameOffset = readInt2( buffer, bufferIndex );
		bufferIndex += 2;

		return bufferIndex - start;
	}
	int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
		int start = bufferIndex;
		SmbFindFileBothDirectoryInfo e;

		lastNameBufferIndex = bufferIndex + lastNameOffset;

		results = new SmbFindFileBothDirectoryInfo[numEntries];
		for( int i = 0; i < numEntries; i++ ) {
			results[i] = e = new SmbFindFileBothDirectoryInfo();

			e.nextEntryOffset = readInt4( buffer, bufferIndex );
			e.fileIndex = readInt4( buffer, bufferIndex + 4 );
			e.creationTime = readTime( buffer, bufferIndex + 8 );
	//		e.lastAccessTime = readTime( buffer, bufferIndex + 16 );
			e.lastWriteTime = readTime( buffer, bufferIndex + 24 );
	//		e.changeTime = readTime( buffer, bufferIndex + 32 );
			e.endOfFile = readLong( buffer, bufferIndex + 40 );
	//		e.allocationSize = readLong( buffer, bufferIndex + 48 );
			e.extFileAttributes = readInt4( buffer, bufferIndex + 56 );
			e.fileNameLength = readInt4( buffer, bufferIndex + 60 );
	//		e.eaSize = readInt4( buffer, bufferIndex + 64 );
	//		e.shortNameLength = buffer[bufferIndex + 68] & 0xFF;

			/* With NT, the shortName is in Unicode regardless of what is negotiated.
			 */

	//		e.shortName = readString( buffer, bufferIndex + 70, e.shortNameLength );
			e.filename = readString( buffer, bufferIndex + 94, e.fileNameLength );

//Log.println( Log.DEBUGGING, "Trans2FindFirst2/Next2Response debugging", "bufferIndex=" + bufferIndex + ",lastNameBufferIndex=" + lastNameBufferIndex + ",nextEntryOffet=" + ( bufferIndex + e.nextEntryOffset ));

			/* lastNameOffset ends up pointing to either to
			 * the exact location of the filename(e.g. Win98)
			 * or to the start of the entry containing the
			 * filename(e.g. NT). Ahhrg! In either case the
			 * lastNameOffset falls between the start of the
			 * entry and the next entry.
			 */

			if( lastNameBufferIndex >= bufferIndex && ( e.nextEntryOffset == 0 ||
						lastNameBufferIndex < ( bufferIndex + e.nextEntryOffset ))) {
				lastName = e.filename;
				resumeKey = e.fileIndex;
			}

//Log.println( Log.DEBUGGING, "info entry", e );

			bufferIndex += e.nextEntryOffset;
		}


		if( lastName == null ) {
			Log.println( Log.WARNINGS, "Trans2FindFirst2/Next2Response debugging",
											"lastName was null" );
		}

		/* last nextEntryOffset for NT 4(but not 98) is 0 so we must
		 * use dataCount or our accounting will report an error for NT :~(
		 */
		
		//return bufferIndex - start;

		return dataCount;
	}
	public String toString() {
		String c;
		if( subCommand == SmbComTransaction.TRANS2_FIND_FIRST2 ) {
			c = "Trans2FindFirst2Response[";
		} else {
			c = "Trans2FindNext2Response[";
		}
		return new String( c + super.toString() +
			",sid=" + sid +
			",searchCount=" + numEntries +
			",isEndOfSearch=" + isEndOfSearch +
			",eaErrorOffset=" + eaErrorOffset +
			",lastNameOffset=" + lastNameOffset +
			",lastName=" + lastName + "]" );
	}
}