Exemple #1
1
  private void loop() {
    while (thread == Thread.currentThread()) {
      try {
        Request key = peekKey();
        if (key == null) throw new IOException("end of stream");
        synchronized (response_map) {
          Response response = (Response) response_map.get(key);
          if (response == null) {
            if (log.level >= 4) log.println("Invalid key, skipping message");
            doSkip();
          } else {
            doRecv(response);
            response.isReceived = true;
            response_map.notifyAll();
          }
        }
      } catch (Exception ex) {
        String msg = ex.getMessage();
        boolean timeout = msg != null && msg.equals("Read timed out");
        /* If just a timeout, try to disconnect gracefully
         */
        boolean hard = timeout == false;

        if (!timeout && log.level >= 3) ex.printStackTrace(log);

        try {
          disconnect(hard);
        } catch (IOException ioe) {
          ioe.printStackTrace(log);
        }
      }
    }
  }
Exemple #2
0
  static {
    int level;
    log = LogStream.getInstance();

    try {
      Config.load(Config.class.getClassLoader().getResourceAsStream("config.properties"));
    } catch (IOException ioe) {
      if (LogStream.level > 0) ioe.printStackTrace(log);
    }

    if ((level = Config.getInt("jcifs.util.loglevel", -1)) != -1) {
      LogStream.setLevel(level);
    }

    try {
      "".getBytes(DEFAULT_OEM_ENCODING);
    } catch (UnsupportedEncodingException uee) {
      if (LogStream.level >= 2) {
        log.println(
            "WARNING: The default OEM encoding "
                + DEFAULT_OEM_ENCODING
                + " does not appear to be supported by this JRE. The default encoding will be US-ASCII.");
      }
      DEFAULT_OEM_ENCODING = "US-ASCII";
    }

    if (LogStream.level >= 4) {
      try {
        prp.store(log, "JCIFS PROPERTIES");
      } catch (IOException ioe) {
      }
    }
  }
Exemple #3
0
 public void disconnect(boolean hard) throws IOException {
   synchronized (setupDiscoLock) {
     synchronized (this) {
       switch (state) {
         case 0: /* not connected - just return */
           return;
         case 2:
           hard = true;
         case 3: /* connected - go ahead and disconnect */
           if (response_map.size() != 0 && !hard) {
             break; /* outstanding requests */
           }
           doDisconnect(hard);
         case 4: /* in error - reset the transport */
           thread = null;
           state = 0;
           break;
         default:
           if (log.level >= 1) log.println("Invalid state: " + state);
           thread = null;
           state = 0;
           break;
       }
     }
   }
 }
Exemple #4
0
 /**
  * Set the default properties of the static Properties used by <tt>Config</tt>. This permits a
  * different Properties object/file to be used as the source of properties for use by the jCIFS
  * library. The Properties must be set <i>before jCIFS classes are accessed</i> as most jCIFS
  * classes load properties statically once. Using this method will also override properties loaded
  * using the <tt>-Djcifs.properties=</tt> commandline parameter.
  */
 public static void setProperties(Properties prp) {
   Config.prp = new Properties(prp);
   try {
     Config.prp.putAll(System.getProperties());
   } catch (SecurityException se) {
     if (LogStream.level > 1)
       log.println("SecurityException: jcifs will ignore System properties");
   }
 }
Exemple #5
0
  public synchronized void connect(long timeout) throws TransportException {
    try {
      switch (state) {
        case 0:
          break;
        case 3:
          return; // already connected
        case 4:
          state = 0;
          throw new TransportException("Connection in error", te);
        default:
          TransportException te = new TransportException("Invalid state: " + state);
          state = 0;
          throw te;
      }

      state = 1;
      te = null;
      thread = new Thread(this, name);
      thread.setDaemon(true);

      synchronized (thread) {
        thread.start();
        thread.wait(timeout); /* wait for doConnect */

        switch (state) {
          case 1: /* doConnect never returned */
            state = 0;
            thread = null;
            throw new TransportException("Connection timeout");
          case 2:
            if (te != null) {
                /* doConnect throw Exception */
              state = 4; /* error */
              thread = null;
              throw te;
            }
            state = 3; /* Success! */
            return;
        }
      }
    } catch (InterruptedException ie) {
      state = 0;
      thread = null;
      throw new TransportException(ie);
    } finally {
      /* This guarantees that we leave in a valid state
       */
      if (state != 0 && state != 3 && state != 4) {
        if (log.level >= 1) log.println("Invalid state: " + state);
        state = 0;
        thread = null;
      }
    }
  }
Exemple #6
0
 /**
  * Load the <code>Config</code> with properties from the stream <code>in</code> from a <code>
  * Properties</code> file.
  */
 public static void load(InputStream in) throws IOException {
   if (in != null) {
     prp.load(in);
   }
   try {
     prp.putAll(System.getProperties());
   } catch (SecurityException se) {
     if (LogStream.level > 1)
       log.println("SecurityException: jcifs will ignore System properties");
   }
 }
  int decode(byte[] buffer, int bufferIndex) {
    int start = headerStart = bufferIndex;

    bufferIndex += readHeaderWireFormat(buffer, bufferIndex);

    wordCount = buffer[bufferIndex++];
    if (wordCount != 0) {
      int n;
      if ((n = readParameterWordsWireFormat(buffer, bufferIndex)) != wordCount * 2) {
        if (log.level >= 5) {
          log.println(
              "wordCount * 2="
                  + (wordCount * 2)
                  + " but readParameterWordsWireFormat returned "
                  + n);
        }
      }
      bufferIndex += wordCount * 2;
    }

    byteCount = readInt2(buffer, bufferIndex);
    bufferIndex += 2;

    if (byteCount != 0) {
      int n;
      if ((n = readBytesWireFormat(buffer, bufferIndex)) != byteCount) {
        if (log.level >= 5) {
          log.println("byteCount=" + byteCount + " but readBytesWireFormat returned " + n);
        }
      }
      // Don't think we can rely on n being correct here. Must use byteCount.
      // Last paragraph of section 3.13.3 eludes to this.

      bufferIndex += byteCount;
    }

    length = bufferIndex - start;
    return length;
  }
Exemple #8
0
 /**
  * Retrieve an <code>InetAddress</code>. If the address is not an IP address and cannot be
  * resolved <code>null</code> will be returned.
  */
 public static InetAddress getInetAddress(String key, InetAddress def) {
   String addr = prp.getProperty(key);
   if (addr != null) {
     try {
       def = InetAddress.getByName(addr);
     } catch (UnknownHostException uhe) {
       if (LogStream.level > 0) {
         log.println(addr);
         uhe.printStackTrace(log);
       }
     }
   }
   return def;
 }
Exemple #9
0
  public static InetAddress getLocalHost() {
    String addr = prp.getProperty("jcifs.smb.client.laddr");

    if (addr != null) {
      try {
        return InetAddress.getByName(addr);
      } catch (UnknownHostException uhe) {
        if (LogStream.level > 0) {
          log.println("Ignoring jcifs.smb.client.laddr address: " + addr);
          uhe.printStackTrace(log);
        }
      }
    }

    return null;
  }
Exemple #10
0
 /**
  * Retrieve an array of <tt>InetAddress</tt> created from a property value containting a
  * <tt>delim</tt> separated list of hostnames and/or ipaddresses.
  */
 public static InetAddress[] getInetAddressArray(String key, String delim, InetAddress[] def) {
   String p = getProperty(key);
   if (p != null) {
     StringTokenizer tok = new StringTokenizer(p, delim);
     int len = tok.countTokens();
     InetAddress[] arr = new InetAddress[len];
     for (int i = 0; i < len; i++) {
       String addr = tok.nextToken();
       try {
         arr[i] = InetAddress.getByName(addr);
       } catch (UnknownHostException uhe) {
         if (LogStream.level > 0) {
           log.println(addr);
           uhe.printStackTrace(log);
         }
         return def;
       }
     }
     return arr;
   }
   return def;
 }
public abstract class ServerMessageBlock extends Response implements Request, SmbConstants {

  static LogStream log = LogStream.getInstance();

  static final byte[] header = {
    (byte) 0xFF, (byte) 'S', (byte) 'M', (byte) 'B',
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
  };

  static void writeInt2(long val, byte[] dst, int dstIndex) {
    dst[dstIndex] = (byte) (val);
    dst[++dstIndex] = (byte) (val >> 8);
  }

  static void writeInt4(long val, byte[] dst, int dstIndex) {
    dst[dstIndex] = (byte) (val);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >> 8);
  }

  static int readInt2(byte[] src, int srcIndex) {
    return (src[srcIndex] & 0xFF) + ((src[srcIndex + 1] & 0xFF) << 8);
  }

  static int readInt4(byte[] src, int srcIndex) {
    return (src[srcIndex] & 0xFF)
        + ((src[srcIndex + 1] & 0xFF) << 8)
        + ((src[srcIndex + 2] & 0xFF) << 16)
        + ((src[srcIndex + 3] & 0xFF) << 24);
  }

  static long readInt8(byte[] src, int srcIndex) {
    return (readInt4(src, srcIndex) & 0xFFFFFFFFL) + ((long) (readInt4(src, srcIndex + 4)) << 32);
  }

  static void writeInt8(long val, byte[] dst, int dstIndex) {
    dst[dstIndex] = (byte) (val);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >>= 8);
    dst[++dstIndex] = (byte) (val >> 8);
  }

  static long readTime(byte[] src, int srcIndex) {
    int low = readInt4(src, srcIndex);
    int hi = readInt4(src, srcIndex + 4);
    long t = ((long) hi << 32L) | (low & 0xFFFFFFFFL);
    t = (t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601);
    return t;
  }

  static void writeTime(long t, byte[] dst, int dstIndex) {
    if (t != 0L) {
      t = (t + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L;
    }
    writeInt8(t, dst, dstIndex);
  }

  static long readUTime(byte[] buffer, int bufferIndex) {
    return readInt4(buffer, bufferIndex) * 1000L;
  }

  static void writeUTime(long t, byte[] dst, int dstIndex) {
    if (t == 0L || t == 0xFFFFFFFFFFFFFFFFL) {
      writeInt4(0xFFFFFFFF, dst, dstIndex);
      return;
    }
    synchronized (TZ) {
      if (TZ.inDaylightTime(new Date())) {
        // in DST
        if (TZ.inDaylightTime(new Date(t))) {
          // t also in DST so no correction
        } else {
          // t not in DST so subtract 1 hour
          t -= 3600000;
        }
      } else {
        // not in DST
        if (TZ.inDaylightTime(new Date(t))) {
          // t is in DST so add 1 hour
          t += 3600000;
        } else {
          // t isn't in DST either
        }
      }
    }
    writeInt4((int) (t / 1000L), dst, dstIndex);
  }

  /*
   * These are all the smbs supported by this library. This includes requests
   * and well as their responses for each type however the actuall implementations
   * of the readXxxWireFormat and writeXxxWireFormat methods may not be in
   * place. For example at the time of this writing the readXxxWireFormat
   * for requests and the writeXxxWireFormat for responses are not implemented
   * and simply return 0. These would need to be completed for a server
   * implementation.
   */

  static final byte SMB_COM_CREATE_DIRECTORY = (byte) 0x00;
  static final byte SMB_COM_DELETE_DIRECTORY = (byte) 0x01;
  static final byte SMB_COM_CLOSE = (byte) 0x04;
  static final byte SMB_COM_DELETE = (byte) 0x06;
  static final byte SMB_COM_RENAME = (byte) 0x07;
  static final byte SMB_COM_QUERY_INFORMATION = (byte) 0x08;
  static final byte SMB_COM_WRITE = (byte) 0x0B;
  static final byte SMB_COM_CHECK_DIRECTORY = (byte) 0x10;
  static final byte SMB_COM_TRANSACTION = (byte) 0x25;
  static final byte SMB_COM_TRANSACTION_SECONDARY = (byte) 0x26;
  static final byte SMB_COM_MOVE = (byte) 0x2A;
  static final byte SMB_COM_ECHO = (byte) 0x2B;
  static final byte SMB_COM_OPEN_ANDX = (byte) 0x2D;
  static final byte SMB_COM_READ_ANDX = (byte) 0x2E;
  static final byte SMB_COM_WRITE_ANDX = (byte) 0x2F;
  static final byte SMB_COM_TRANSACTION2 = (byte) 0x32;
  static final byte SMB_COM_FIND_CLOSE2 = (byte) 0x34;
  static final byte SMB_COM_TREE_DISCONNECT = (byte) 0x71;
  static final byte SMB_COM_NEGOTIATE = (byte) 0x72;
  static final byte SMB_COM_SESSION_SETUP_ANDX = (byte) 0x73;
  static final byte SMB_COM_LOGOFF_ANDX = (byte) 0x74;
  static final byte SMB_COM_TREE_CONNECT_ANDX = (byte) 0x75;
  static final byte SMB_COM_NT_TRANSACT = (byte) 0xA0;
  static final byte SMB_COM_NT_TRANSACT_SECONDARY = (byte) 0xA1;
  static final byte SMB_COM_NT_CREATE_ANDX = (byte) 0xA2;

  /*
   * Some fields specify the offset from the beginning of the header. This
   * field should be used for calculating that. This would likely be zero
   * but an implemantation that encorporates the transport header(for
   * efficiency) might use a different initial bufferIndex. For example,
   * to eliminate copying data when writing NbtSession data one might
   * manage that 4 byte header specifically and therefore the initial
   * bufferIndex, and thus headerStart, would be 4).(NOTE: If one where
   * looking for a way to improve perfomance this is precisly what you
   * would want to do as the jcifs.netbios.SocketXxxputStream classes
   * arraycopy all data read or written into a new buffer shifted over 4!)
   */

  byte command, flags;
  int headerStart, length, batchLevel, errorCode, flags2, tid, pid, uid, mid, wordCount, byteCount;
  boolean useUnicode, received, extendedSecurity;
  long responseTimeout = 1;
  int signSeq;
  boolean verifyFailed;
  NtlmPasswordAuthentication auth = null;
  String path;
  SigningDigest digest = null;
  ServerMessageBlock response;

  ServerMessageBlock() {
    flags = (byte) (FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED);
    pid = PID;
    batchLevel = 0;
  }

  void reset() {
    flags = (byte) (FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED);
    flags2 = 0;
    errorCode = 0;
    received = false;
    digest = null;
  }

  int writeString(String str, byte[] dst, int dstIndex) {
    return writeString(str, dst, dstIndex, useUnicode);
  }

  int writeString(String str, byte[] dst, int dstIndex, boolean useUnicode) {
    int start = dstIndex;

    try {
      if (useUnicode) {
        // Unicode requires word alignment
        if (((dstIndex - headerStart) % 2) != 0) {
          dst[dstIndex++] = (byte) '\0';
        }
        System.arraycopy(str.getBytes(UNI_ENCODING), 0, dst, dstIndex, str.length() * 2);
        dstIndex += str.length() * 2;
        dst[dstIndex++] = (byte) '\0';
        dst[dstIndex++] = (byte) '\0';
      } else {
        byte[] b = str.getBytes(OEM_ENCODING);
        System.arraycopy(b, 0, dst, dstIndex, b.length);
        dstIndex += b.length;
        dst[dstIndex++] = (byte) '\0';
      }
    } catch (UnsupportedEncodingException uee) {
      if (log.level > 1) uee.printStackTrace(log);
    }

    return dstIndex - start;
  }

  String readString(byte[] src, int srcIndex) {
    return readString(src, srcIndex, 256, useUnicode);
  }

  String readString(byte[] src, int srcIndex, int maxLen, boolean useUnicode) {
    int len = 0;
    String str = null;
    try {
      if (useUnicode) {
        // Unicode requires word alignment
        if (((srcIndex - headerStart) % 2) != 0) {
          srcIndex++;
        }
        while (src[srcIndex + len] != (byte) 0x00 || src[srcIndex + len + 1] != (byte) 0x00) {
          len += 2;
          if (len > maxLen) {
            if (log.level > 0)
              Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
            throw new RuntimeException("zero termination not found");
          }
        }
        str = new String(src, srcIndex, len, UNI_ENCODING);
      } else {
        while (src[srcIndex + len] != (byte) 0x00) {
          len++;
          if (len > maxLen) {
            if (log.level > 0)
              Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
            throw new RuntimeException("zero termination not found");
          }
        }
        str = new String(src, srcIndex, len, OEM_ENCODING);
      }
    } catch (UnsupportedEncodingException uee) {
      if (log.level > 1) uee.printStackTrace(log);
    }
    return str;
  }

  String readString(byte[] src, int srcIndex, int srcEnd, int maxLen, boolean useUnicode) {
    int len = 0;
    String str = null;
    try {
      if (useUnicode) {
        // Unicode requires word alignment
        if (((srcIndex - headerStart) % 2) != 0) {
          srcIndex++;
        }
        for (len = 0; (srcIndex + len + 1) < srcEnd; len += 2) {
          if (src[srcIndex + len] == (byte) 0x00 && src[srcIndex + len + 1] == (byte) 0x00) {
            break;
          }
          if (len > maxLen) {
            if (log.level > 0)
              Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
            throw new RuntimeException("zero termination not found");
          }
        }
        str = new String(src, srcIndex, len, UNI_ENCODING);
      } else {
        for (len = 0; srcIndex < srcEnd; len++) {
          if (src[srcIndex + len] == (byte) 0x00) {
            break;
          }
          if (len > maxLen) {
            if (log.level > 0)
              Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
            throw new RuntimeException("zero termination not found");
          }
        }
        str = new String(src, srcIndex, len, OEM_ENCODING);
      }
    } catch (UnsupportedEncodingException uee) {
      if (log.level > 1) uee.printStackTrace(log);
    }
    return str;
  }

  int stringWireLength(String str, int offset) {
    int len = str.length() + 1;
    if (useUnicode) {
      len = str.length() * 2 + 2;
      len = (offset % 2) != 0 ? len + 1 : len;
    }
    return len;
  }

  int readStringLength(byte[] src, int srcIndex, int max) {
    int len = 0;
    while (src[srcIndex + len] != (byte) 0x00) {
      if (len++ > max) {
        throw new RuntimeException("zero termination not found: " + this);
      }
    }
    return len;
  }

  int encode(byte[] dst, int dstIndex) {
    int start = headerStart = dstIndex;

    dstIndex += writeHeaderWireFormat(dst, dstIndex);
    wordCount = writeParameterWordsWireFormat(dst, dstIndex + 1);
    dst[dstIndex++] = (byte) ((wordCount / 2) & 0xFF);
    dstIndex += wordCount;
    wordCount /= 2;
    byteCount = writeBytesWireFormat(dst, dstIndex + 2);
    dst[dstIndex++] = (byte) (byteCount & 0xFF);
    dst[dstIndex++] = (byte) ((byteCount >> 8) & 0xFF);
    dstIndex += byteCount;

    length = dstIndex - start;

    if (digest != null) {
      digest.sign(dst, headerStart, length, this, response);
    }

    return length;
  }

  int decode(byte[] buffer, int bufferIndex) {
    int start = headerStart = bufferIndex;

    bufferIndex += readHeaderWireFormat(buffer, bufferIndex);

    wordCount = buffer[bufferIndex++];
    if (wordCount != 0) {
      int n;
      if ((n = readParameterWordsWireFormat(buffer, bufferIndex)) != wordCount * 2) {
        if (log.level >= 5) {
          log.println(
              "wordCount * 2="
                  + (wordCount * 2)
                  + " but readParameterWordsWireFormat returned "
                  + n);
        }
      }
      bufferIndex += wordCount * 2;
    }

    byteCount = readInt2(buffer, bufferIndex);
    bufferIndex += 2;

    if (byteCount != 0) {
      int n;
      if ((n = readBytesWireFormat(buffer, bufferIndex)) != byteCount) {
        if (log.level >= 5) {
          log.println("byteCount=" + byteCount + " but readBytesWireFormat returned " + n);
        }
      }
      // Don't think we can rely on n being correct here. Must use byteCount.
      // Last paragraph of section 3.13.3 eludes to this.

      bufferIndex += byteCount;
    }

    length = bufferIndex - start;
    return length;
  }

  int writeHeaderWireFormat(byte[] dst, int dstIndex) {
    System.arraycopy(header, 0, dst, dstIndex, header.length);
    dst[dstIndex + CMD_OFFSET] = command;
    dst[dstIndex + FLAGS_OFFSET] = flags;
    writeInt2(flags2, dst, dstIndex + FLAGS_OFFSET + 1);
    dstIndex += TID_OFFSET;
    writeInt2(tid, dst, dstIndex);
    writeInt2(pid, dst, dstIndex + 2);
    writeInt2(uid, dst, dstIndex + 4);
    writeInt2(mid, dst, dstIndex + 6);
    return HEADER_LENGTH;
  }

  int readHeaderWireFormat(byte[] buffer, int bufferIndex) {
    command = buffer[bufferIndex + CMD_OFFSET];
    errorCode = readInt4(buffer, bufferIndex + ERROR_CODE_OFFSET);
    flags = buffer[bufferIndex + FLAGS_OFFSET];
    flags2 = readInt2(buffer, bufferIndex + FLAGS_OFFSET + 1);
    tid = readInt2(buffer, bufferIndex + TID_OFFSET);
    pid = readInt2(buffer, bufferIndex + TID_OFFSET + 2);
    uid = readInt2(buffer, bufferIndex + TID_OFFSET + 4);
    mid = readInt2(buffer, bufferIndex + TID_OFFSET + 6);
    return HEADER_LENGTH;
  }

  boolean isResponse() {
    return (flags & FLAGS_RESPONSE) == FLAGS_RESPONSE;
  }

  /*
   * For this packet deconstruction technique to work for
   * other networking protocols the InputStream may need
   * to be passed to the readXxxWireFormat methods. This is
   * actually purer. However, in the case of smb we know the
   * wordCount and byteCount. And since every subclass of
   * ServerMessageBlock would have to perform the same read
   * operation on the input stream, we might as will pull that
   * common functionality into the superclass and read wordCount
   * and byteCount worth of data.
   *
   * We will still use the readXxxWireFormat return values to
   * indicate how many bytes(note: readParameterWordsWireFormat
   * returns bytes read and not the number of words(but the
   * wordCount member DOES store the number of words)) we
   * actually read. Incedentally this is important to the
   * AndXServerMessageBlock class that needs to potentially
   * read in another smb's parameter words and bytes based on
   * information in it's andxCommand, andxOffset, ...etc.
   */

  abstract int writeParameterWordsWireFormat(byte[] dst, int dstIndex);

  abstract int writeBytesWireFormat(byte[] dst, int dstIndex);

  abstract int readParameterWordsWireFormat(byte[] buffer, int bufferIndex);

  abstract int readBytesWireFormat(byte[] buffer, int bufferIndex);

  public int hashCode() {
    return mid;
  }

  public boolean equals(Object obj) {
    return obj instanceof ServerMessageBlock && ((ServerMessageBlock) obj).mid == mid;
  }

  public String toString() {
    String c;
    switch (command) {
      case SMB_COM_NEGOTIATE:
        c = "SMB_COM_NEGOTIATE";
        break;
      case SMB_COM_SESSION_SETUP_ANDX:
        c = "SMB_COM_SESSION_SETUP_ANDX";
        break;
      case SMB_COM_TREE_CONNECT_ANDX:
        c = "SMB_COM_TREE_CONNECT_ANDX";
        break;
      case SMB_COM_QUERY_INFORMATION:
        c = "SMB_COM_QUERY_INFORMATION";
        break;
      case SMB_COM_CHECK_DIRECTORY:
        c = "SMB_COM_CHECK_DIRECTORY";
        break;
      case SMB_COM_TRANSACTION:
        c = "SMB_COM_TRANSACTION";
        break;
      case SMB_COM_TRANSACTION2:
        c = "SMB_COM_TRANSACTION2";
        break;
      case SMB_COM_TRANSACTION_SECONDARY:
        c = "SMB_COM_TRANSACTION_SECONDARY";
        break;
      case SMB_COM_FIND_CLOSE2:
        c = "SMB_COM_FIND_CLOSE2";
        break;
      case SMB_COM_TREE_DISCONNECT:
        c = "SMB_COM_TREE_DISCONNECT";
        break;
      case SMB_COM_LOGOFF_ANDX:
        c = "SMB_COM_LOGOFF_ANDX";
        break;
      case SMB_COM_ECHO:
        c = "SMB_COM_ECHO";
        break;
      case SMB_COM_MOVE:
        c = "SMB_COM_MOVE";
        break;
      case SMB_COM_RENAME:
        c = "SMB_COM_RENAME";
        break;
      case SMB_COM_DELETE:
        c = "SMB_COM_DELETE";
        break;
      case SMB_COM_DELETE_DIRECTORY:
        c = "SMB_COM_DELETE_DIRECTORY";
        break;
      case SMB_COM_NT_CREATE_ANDX:
        c = "SMB_COM_NT_CREATE_ANDX";
        break;
      case SMB_COM_OPEN_ANDX:
        c = "SMB_COM_OPEN_ANDX";
        break;
      case SMB_COM_READ_ANDX:
        c = "SMB_COM_READ_ANDX";
        break;
      case SMB_COM_CLOSE:
        c = "SMB_COM_CLOSE";
        break;
      case SMB_COM_WRITE_ANDX:
        c = "SMB_COM_WRITE_ANDX";
        break;
      case SMB_COM_CREATE_DIRECTORY:
        c = "SMB_COM_CREATE_DIRECTORY";
        break;
      case SMB_COM_NT_TRANSACT:
        c = "SMB_COM_NT_TRANSACT";
        break;
      case SMB_COM_NT_TRANSACT_SECONDARY:
        c = "SMB_COM_NT_TRANSACT_SECONDARY";
        break;
      default:
        c = "UNKNOWN";
    }
    String str = errorCode == 0 ? "0" : SmbException.getMessageByCode(errorCode);
    return new String(
        "command="
            + c
            + ",received="
            + received
            + ",errorCode="
            + str
            + ",flags=0x"
            + Hexdump.toHexString(flags & 0xFF, 4)
            + ",flags2=0x"
            + Hexdump.toHexString(flags2, 4)
            + ",signSeq="
            + signSeq
            + ",tid="
            + tid
            + ",pid="
            + pid
            + ",uid="
            + uid
            + ",mid="
            + mid
            + ",wordCount="
            + wordCount
            + ",byteCount="
            + byteCount);
  }

  public String toShortString() {
    String c;
    switch (command) {
      case SMB_COM_NEGOTIATE:
        c = "SMB_COM_NEGOTIATE";
        break;
      case SMB_COM_SESSION_SETUP_ANDX:
        c = "SMB_COM_SESSION_SETUP_ANDX";
        break;
      case SMB_COM_TREE_CONNECT_ANDX:
        c = "SMB_COM_TREE_CONNECT_ANDX";
        break;
      case SMB_COM_QUERY_INFORMATION:
        c = "SMB_COM_QUERY_INFORMATION";
        break;
      case SMB_COM_CHECK_DIRECTORY:
        c = "SMB_COM_CHECK_DIRECTORY";
        break;
      case SMB_COM_TRANSACTION:
        c = "SMB_COM_TRANSACTION";
        break;
      case SMB_COM_TRANSACTION2:
        c = "SMB_COM_TRANSACTION2";
        break;
      case SMB_COM_TRANSACTION_SECONDARY:
        c = "SMB_COM_TRANSACTION_SECONDARY";
        break;
      case SMB_COM_FIND_CLOSE2:
        c = "SMB_COM_FIND_CLOSE2";
        break;
      case SMB_COM_TREE_DISCONNECT:
        c = "SMB_COM_TREE_DISCONNECT";
        break;
      case SMB_COM_LOGOFF_ANDX:
        c = "SMB_COM_LOGOFF_ANDX";
        break;
      case SMB_COM_ECHO:
        c = "SMB_COM_ECHO";
        break;
      case SMB_COM_MOVE:
        c = "SMB_COM_MOVE";
        break;
      case SMB_COM_RENAME:
        c = "SMB_COM_RENAME";
        break;
      case SMB_COM_DELETE:
        c = "SMB_COM_DELETE";
        break;
      case SMB_COM_DELETE_DIRECTORY:
        c = "SMB_COM_DELETE_DIRECTORY";
        break;
      case SMB_COM_NT_CREATE_ANDX:
        c = "SMB_COM_NT_CREATE_ANDX";
        break;
      case SMB_COM_OPEN_ANDX:
        c = "SMB_COM_OPEN_ANDX";
        break;
      case SMB_COM_READ_ANDX:
        c = "SMB_COM_READ_ANDX";
        break;
      case SMB_COM_CLOSE:
        c = "SMB_COM_CLOSE";
        break;
      case SMB_COM_WRITE_ANDX:
        c = "SMB_COM_WRITE_ANDX";
        break;
      case SMB_COM_CREATE_DIRECTORY:
        c = "SMB_COM_CREATE_DIRECTORY";
        break;
      case SMB_COM_NT_TRANSACT:
        c = "SMB_COM_NT_TRANSACT";
        break;
      case SMB_COM_NT_TRANSACT_SECONDARY:
        c = "SMB_COM_NT_TRANSACT_SECONDARY";
        break;
      default:
        c = "UNKNOWN";
    }
    String ret = "command=" + c;
    if (received) ret += ",received";
    if (errorCode != 0) ret += ",errorCode=" + SmbException.getMessageByCode(errorCode);
    if (byteCount > 0) ret += ",byteCount=" + byteCount;
    return ret;
  }
}
Exemple #12
0
/**
 * This class simplifies communication for protocols that support multiplexing requests. It
 * encapsulates a stream and some protocol knowledge (provided by a concrete subclass) so that
 * connecting, disconnecting, sending, and receiving can be syncronized properly. Apparatus is
 * provided to send and receive requests concurrently.
 */
public abstract class Transport implements Runnable {

  static int id = 0;
  static LogStream log = LogStream.getInstance();

  public static int readn(InputStream in, byte[] b, int off, int len) throws IOException {
    int i = 0, n = -5;

    while (i < len) {
      n = in.read(b, off + i, len - i);
      if (n <= 0) {
        break;
      }
      i += n;
    }

    return i;
  }

  /* state values
   * 0 - not connected
   * 1 - connecting
   * 2 - run connected
   * 3 - connected
   * 4 - error
   */
  int state = 0;

  String name = "Transport" + id++;
  Thread thread;
  TransportException te;

  protected HashMap response_map = new HashMap(4);

  protected abstract void makeKey(Request request) throws IOException;

  protected abstract Request peekKey() throws IOException;

  protected abstract void doSend(Request request) throws IOException;

  protected abstract void doRecv(Response response) throws IOException;

  protected abstract void doSkip() throws IOException;

  public Object setupDiscoLock = new Object();

  public void sendrecv(Request request, Response response, long timeout) throws IOException {
    synchronized (response_map) {
      makeKey(request);
      response.isReceived = false;
      try {
        response_map.put(request, response);
        doSend(request);
        response.expiration = System.currentTimeMillis() + timeout;
        while (!response.isReceived) {
          response_map.wait(timeout);
          timeout = response.expiration - System.currentTimeMillis();
          if (timeout <= 0) {
            throw new TransportException(name + " timedout waiting for response to " + request);
          }
        }
      } catch (IOException ioe) {
        if (log.level > 2) ioe.printStackTrace(log);
        try {
          disconnect(true);
        } catch (IOException ioe2) {
          ioe2.printStackTrace(log);
        }
        throw ioe;
      } catch (InterruptedException ie) {
        throw new TransportException(ie);
      } finally {
        response_map.remove(request);
      }
    }
  }

  private void loop() {
    while (thread == Thread.currentThread()) {
      try {
        Request key = peekKey();
        if (key == null) throw new IOException("end of stream");
        synchronized (response_map) {
          Response response = (Response) response_map.get(key);
          if (response == null) {
            if (log.level >= 4) log.println("Invalid key, skipping message");
            doSkip();
          } else {
            doRecv(response);
            response.isReceived = true;
            response_map.notifyAll();
          }
        }
      } catch (Exception ex) {
        String msg = ex.getMessage();
        boolean timeout = msg != null && msg.equals("Read timed out");
        /* If just a timeout, try to disconnect gracefully
         */
        boolean hard = timeout == false;

        if (!timeout && log.level >= 3) ex.printStackTrace(log);

        try {
          disconnect(hard);
        } catch (IOException ioe) {
          ioe.printStackTrace(log);
        }
      }
    }
  }

  /* Build a connection. Only one thread will ever call this method at
   * any one time. If this method throws an exception or the connect timeout
   * expires an encapsulating TransportException will be thrown from connect
   * and the transport will be in error.
   */

  protected abstract void doConnect() throws Exception;

  /* Tear down a connection. If the hard parameter is true, the diconnection
   * procedure should not initiate or wait for any outstanding requests on
   * this transport.
   */

  protected abstract void doDisconnect(boolean hard) throws IOException;

  public synchronized void connect(long timeout) throws TransportException {
    try {
      switch (state) {
        case 0:
          break;
        case 3:
          return; // already connected
        case 4:
          state = 0;
          throw new TransportException("Connection in error", te);
        default:
          TransportException te = new TransportException("Invalid state: " + state);
          state = 0;
          throw te;
      }

      state = 1;
      te = null;
      thread = new Thread(this, name);
      thread.setDaemon(true);

      synchronized (thread) {
        thread.start();
        thread.wait(timeout); /* wait for doConnect */

        switch (state) {
          case 1: /* doConnect never returned */
            state = 0;
            thread = null;
            throw new TransportException("Connection timeout");
          case 2:
            if (te != null) {
                /* doConnect throw Exception */
              state = 4; /* error */
              thread = null;
              throw te;
            }
            state = 3; /* Success! */
            return;
        }
      }
    } catch (InterruptedException ie) {
      state = 0;
      thread = null;
      throw new TransportException(ie);
    } finally {
      /* This guarantees that we leave in a valid state
       */
      if (state != 0 && state != 3 && state != 4) {
        if (log.level >= 1) log.println("Invalid state: " + state);
        state = 0;
        thread = null;
      }
    }
  }

  public void disconnect(boolean hard) throws IOException {
    synchronized (setupDiscoLock) {
      synchronized (this) {
        switch (state) {
          case 0: /* not connected - just return */
            return;
          case 2:
            hard = true;
          case 3: /* connected - go ahead and disconnect */
            if (response_map.size() != 0 && !hard) {
              break; /* outstanding requests */
            }
            doDisconnect(hard);
          case 4: /* in error - reset the transport */
            thread = null;
            state = 0;
            break;
          default:
            if (log.level >= 1) log.println("Invalid state: " + state);
            thread = null;
            state = 0;
            break;
        }
      }
    }
  }

  public void run() {
    Thread run_thread = Thread.currentThread();
    Exception ex0 = null;

    try {
      /* We cannot synchronize (run_thread) here or the caller's
       * thread.wait( timeout ) cannot reaquire the lock and
       * return which would render the timeout effectively useless.
       */
      doConnect();
    } catch (Exception ex) {
      ex0 = ex; // Defer to below where we're locked
      return;
    } finally {
      synchronized (run_thread) {
        if (run_thread != thread) {
          /* Thread no longer the one setup for this transport --
           * doConnect returned too late, just ignore.
           */
          if (ex0 != null) {
            ex0.printStackTrace();
          }
          return;
        }
        if (ex0 != null) {
          te = new TransportException(ex0);
        }
        state = 2; // run connected
        run_thread.notify();
      }
    }

    /* Proccess responses
     */
    loop();
  }

  public String toString() {
    return name;
  }
}