@Override
 public void onCreate(Bundle icicle) {
   super.onCreate(icicle);
   Utils.showMenu(this);
   initialize();
   if (connection != null && connection.isReadyForConnection()) continueConnecting();
 }
Ejemplo n.º 2
0
  void initializeBitmap(int dx, int dy) throws IOException {
    Log.i(TAG, "Desktop name is " + rfbconn.desktopName());
    Log.i(
        TAG, "Desktop size is " + rfbconn.framebufferWidth() + " x " + rfbconn.framebufferHeight());
    int fbsize = rfbconn.framebufferWidth() * rfbconn.framebufferHeight();
    capacity =
        BCFactory.getInstance()
            .getBCActivityManager()
            .getMemoryClass(Utils.getActivityManager(getContext()));

    if (connection.getForceFull() == BitmapImplHint.AUTO) {
      if (fbsize * CompactBitmapData.CAPACITY_MULTIPLIER <= capacity * 1024 * 1024) {
        useFull = true;
        compact = true;
      } else if (fbsize * FullBufferBitmapData.CAPACITY_MULTIPLIER <= capacity * 1024 * 1024) {
        useFull = true;
      } else {
        useFull = false;
      }
    } else useFull = (connection.getForceFull() == BitmapImplHint.FULL);

    if (!useFull) {
      bitmapData = new LargeBitmapData(rfbconn, this, dx, dy, capacity);
      android.util.Log.i(TAG, "Using LargeBitmapData.");
    } else {
      try {
        // TODO: Remove this if Android 4.2 receives a fix which causes it to stop drawing
        // the bitmap in CompactBitmapData when under load (say playing a video over VNC).
        if (!compact || android.os.Build.VERSION.SDK_INT == 17) {
          bitmapData = new FullBufferBitmapData(rfbconn, this, capacity);
          android.util.Log.i(TAG, "Using FullBufferBitmapData.");
        } else {
          bitmapData = new CompactBitmapData(rfbconn, this);
          android.util.Log.i(TAG, "Using CompactBufferBitmapData.");
        }
      } catch (Throwable e) { // If despite our efforts we fail to allocate memory, use LBBM.
        if (bitmapData != null) bitmapData.dispose();
        bitmapData = null;
        System.gc();
        useFull = false;
        bitmapData = new LargeBitmapData(rfbconn, this, dx, dy, capacity);
        android.util.Log.i(TAG, "Using LargeBitmapData.");
      }
    }

    decoder.setBitmapData(bitmapData);
  }
  void initialize() {
    if (android.os.Build.VERSION.SDK_INT >= 9) {
      android.os.StrictMode.ThreadPolicy policy =
          new android.os.StrictMode.ThreadPolicy.Builder().permitAll().build();
      android.os.StrictMode.setThreadPolicy(policy);
    }

    handler = new Handler();

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow()
        .setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    database = new Database(this);

    Intent i = getIntent();
    connection = null;

    Uri data = i.getData();

    boolean isSupportedScheme = false;
    if (data != null) {
      String s = data.getScheme();
      isSupportedScheme = s.equals("rdp") || s.equals("spice") || s.equals("vnc");
    }

    if (isSupportedScheme || !Utils.isNullOrEmptry(i.getType())) {
      if (isMasterPasswordEnabled()) {
        Utils.showFatalErrorMessage(
            this, getResources().getString(R.string.master_password_error_intents_not_supported));
        return;
      }

      connection = ConnectionBean.createLoadFromUri(data, this);

      String host = data.getHost();
      if (!host.startsWith(Constants.CONNECTION)) {
        connection.parseFromUri(data);
      }

      if (connection.isSaved()) {
        connection.saveAndWriteRecent(false);
      }
      // we need to save the connection to display the loading screen, so otherwise we should exit
      if (!connection.isReadyForConnection()) {
        if (!connection.isSaved()) {
          Log.i(TAG, "Exiting - Insufficent information to connect and connection was not saved.");
          Toast.makeText(this, getString(R.string.error_uri_noinfo_nosave), Toast.LENGTH_LONG)
              .show();
          ;
        } else {
          // launch bVNC activity
          Log.i(TAG, "Insufficent information to connect, showing connection dialog.");
          Intent bVncIntent = new Intent(this, bVNC.class);
          startActivity(bVncIntent);
        }
        finish();
        return;
      }
    } else {
      connection = new ConnectionBean(this);
      Bundle extras = i.getExtras();

      if (extras != null) {
        connection.Gen_populate((ContentValues) extras.getParcelable(Constants.CONNECTION));
      }

      // Parse a HOST:PORT entry
      String host = connection.getAddress();
      if (host.indexOf(':') > -1) {
        String p = host.substring(host.indexOf(':') + 1);
        try {
          connection.setPort(Integer.parseInt(p));
        } catch (Exception e) {
        }
        connection.setAddress(host.substring(0, host.indexOf(':')));
      }

      if (connection.getPort() == 0) connection.setPort(Constants.DEFAULT_VNC_PORT);

      if (connection.getSshPort() == 0) connection.setSshPort(Constants.DEFAULT_SSH_PORT);
    }
  }
  void parseFromUri(Uri dataUri) {
    Log.i(TAG, "Parsing VNC URI.");
    if (dataUri == null) {
      m_isReadyForConnection = false;
      m_saved = true;
      return;
    }

    String host = dataUri.getHost();
    if (host != null) {
      setAddress(host);

      // by default, the connection name is the host name
      String nickName = getNickname();
      if (Utils.isNullOrEmptry(nickName)) {
        setNickname(host);
      }

      // default to use same host for ssh
      if (Utils.isNullOrEmptry(getSshServer())) {
        setSshServer(host);
      }
    }

    final int PORT_NONE = -1;
    int port = dataUri.getPort();
    if (port != PORT_NONE) {
      if (!isValidPort(port))
        throw new IllegalArgumentException("The specified VNC port is not valid.");
      setPort(port);
    }

    // handle legacy android-vnc-viewer parsing vnc://host:port/colormodel/password
    List<String> path = dataUri.getPathSegments();
    if (path.size() >= 1) {
      setColorModel(path.get(0));
    }

    if (path.size() >= 2) {
      setPassword(path.get(1));
    }

    // query based parameters
    String connectionName = dataUri.getQueryParameter(Constants.PARAM_CONN_NAME);

    if (connectionName != null) {
      setNickname(connectionName);
    }

    ArrayList<String> supportedUserParams =
        new ArrayList<String>() {
          {
            add(Constants.PARAM_RDP_USER);
            add(Constants.PARAM_SPICE_USER);
            add(Constants.PARAM_VNC_USER);
          }
        };
    for (String userParam : supportedUserParams) {
      String username = dataUri.getQueryParameter(userParam);
      if (username != null) {
        setUserName(username);
        break;
      }
    }

    ArrayList<String> supportedPwdParams =
        new ArrayList<String>() {
          {
            add(Constants.PARAM_RDP_PWD);
            add(Constants.PARAM_SPICE_PWD);
            add(Constants.PARAM_VNC_PWD);
          }
        };
    for (String pwdParam : supportedPwdParams) {
      String password = dataUri.getQueryParameter(pwdParam);
      if (password != null) {
        setPassword(password);
        break;
      }
    }

    setKeepPassword(false); // we should not store the password unless it is encrypted

    String securityTypeParam = dataUri.getQueryParameter(Constants.PARAM_SECTYPE);
    int secType = 0; // invalid
    if (securityTypeParam != null) {
      secType = Integer.parseInt(securityTypeParam); // throw if invalid
      switch (secType) {
        case Constants.SECTYPE_NONE:
        case Constants.SECTYPE_VNC:
          setConnectionType(Constants.CONN_TYPE_PLAIN);
          break;
        case Constants.SECTYPE_INTEGRATED_SSH:
          setConnectionType(Constants.CONN_TYPE_SSH);
          break;
        case Constants.SECTYPE_ULTRA:
          setConnectionType(Constants.CONN_TYPE_ULTRAVNC);
          break;
        case Constants.SECTYPE_TLS:
          setConnectionType(Constants.CONN_TYPE_ANONTLS);
          break;
        case Constants.SECTYPE_VENCRYPT:
          setConnectionType(Constants.CONN_TYPE_VENCRYPT);
          break;
        case Constants.SECTYPE_TUNNEL:
          setConnectionType(Constants.CONN_TYPE_STUNNEL);
          break;
        default:
          throw new IllegalArgumentException(
              "The specified security type is invalid or unsupported.");
      }
    }

    // ssh parameters
    String sshHost = dataUri.getQueryParameter(Constants.PARAM_SSH_HOST);
    if (sshHost != null) {
      setSshServer(sshHost);
    }

    String sshPortParam = dataUri.getQueryParameter(Constants.PARAM_SSH_PORT);
    if (sshPortParam != null) {
      int sshPort = Integer.parseInt(sshPortParam);
      if (!isValidPort(sshPort))
        throw new IllegalArgumentException("The specified SSH port is not valid.");
      setSshPort(sshPort);
    }

    String sshUser = dataUri.getQueryParameter(Constants.PARAM_SSH_USER);
    if (sshUser != null) {
      setSshUser(sshUser);
    }

    String sshPassword = dataUri.getQueryParameter(Constants.PARAM_SSH_PWD);
    if (sshPassword != null) {
      setSshPassword(sshPassword);
    }

    // security hashes
    String idHashAlgParam = dataUri.getQueryParameter(Constants.PARAM_ID_HASH_ALG);
    if (idHashAlgParam != null) {
      int idHashAlg = Integer.parseInt(idHashAlgParam); // throw if invalid
      switch (idHashAlg) {
        case Constants.ID_HASH_MD5:
        case Constants.ID_HASH_SHA1:
        case Constants.ID_HASH_SHA256:
          setIdHashAlgorithm(idHashAlg);
          break;
        default:
          // we are given a bad parameter
          throw new IllegalArgumentException(
              "The specified hash algorithm is invalid or unsupported.");
      }
    }

    String idHash = dataUri.getQueryParameter(Constants.PARAM_ID_HASH);
    if (idHash != null) {
      setIdHash(idHash);
    }

    // color model
    String colorModelParam = dataUri.getQueryParameter(Constants.PARAM_COLORMODEL);
    if (colorModelParam != null) {
      int colorModel = Integer.parseInt(colorModelParam); // throw if invalid
      switch (colorModel) {
        case Constants.COLORMODEL_BLACK_AND_WHITE:
          setColorModel(COLORMODEL.C2.nameString());
          break;
        case Constants.COLORMODEL_GREYSCALE:
          setColorModel(COLORMODEL.C4.nameString());
          break;
        case Constants.COLORMODEL_8_COLORS:
          setColorModel(COLORMODEL.C8.nameString());
          break;
        case Constants.COLORMODEL_64_COLORS:
          setColorModel(COLORMODEL.C64.nameString());
          break;
        case Constants.COLORMODEL_256_COLORS:
          setColorModel(COLORMODEL.C256.nameString());
          break;
          // use the best currently available model
        case Constants.COLORMODEL_16BIT:
          setColorModel(COLORMODEL.C24bit.nameString());
          break;
        case Constants.COLORMODEL_24BIT:
          setColorModel(COLORMODEL.C24bit.nameString());
          break;
        case Constants.COLORMODEL_32BIT:
          setColorModel(COLORMODEL.C24bit.nameString());
          break;
        default:
          // we are given a bad parameter
          throw new IllegalArgumentException(
              "The specified color model is invalid or unsupported.");
      }
    }
    String saveConnectionParam = dataUri.getQueryParameter(Constants.PARAM_SAVE_CONN);
    boolean saveConnection = true;
    if (saveConnectionParam != null) {
      saveConnection = Boolean.parseBoolean(saveConnectionParam); // throw if invalid
    }

    // if we are going to save the connection, we will do so here
    // it may make sense to confirm overwriting data but is probably unnecessary
    if (saveConnection) {
      Database database = new Database(c);
      save(database.getWritableDatabase());
      database.close();
      m_saved = true;
    }

    // we do not currently use API keys

    // check if we need to show data-entry screen
    // it may be possible to prompt for data later
    m_isReadyForConnection = true;
    if (Utils.isNullOrEmptry(getAddress())) {
      m_isReadyForConnection = false;
      Log.i(TAG, "URI missing remote address.");
    }

    int connType = getConnectionType();
    if (secType == Constants.SECTYPE_VNC
        || connType == Constants.CONN_TYPE_STUNNEL
        || connType == Constants.CONN_TYPE_SSH) {
      // we can infer a password is required
      // while we could have implemented tunnel/ssh without one
      // the user can supply a blank value and the server will not
      // request it and it is better to support the common case
      if (Utils.isNullOrEmptry(getPassword())) {
        m_isReadyForConnection = false;
        Log.i(TAG, "URI missing VNC password.");
      }
    }
    if (connType == Constants.CONN_TYPE_SSH) {
      // the below should not occur
      if (Utils.isNullOrEmptry(getSshServer())) m_isReadyForConnection = false;
      // we probably need either a username/password or a key
      // however the main screen doesn't validate this
    }
    // some other types probably require a username/password
    // however main screen doesn't validate this
  }
Ejemplo n.º 5
0
        @Override
        public void handleMessage(Message msg) {
          switch (msg.what) {
            case VncConstants.DIALOG_X509_CERT:
              final X509Certificate cert = (X509Certificate) msg.obj;

              if (connection.getSshHostKey().equals("")) {
                // Show a dialog with the key signature for approval.
                DialogInterface.OnClickListener signatureNo =
                    new DialogInterface.OnClickListener() {
                      @Override
                      public void onClick(DialogInterface dialog, int which) {
                        // We were told not to continue, so stop the activity
                        closeConnection();
                        ((Activity) getContext()).finish();
                      }
                    };
                DialogInterface.OnClickListener signatureYes =
                    new DialogInterface.OnClickListener() {
                      @Override
                      public void onClick(DialogInterface dialog, int which) {
                        // We were told to go ahead with the connection, so save the key into the
                        // database.
                        String certificate = null;
                        try {
                          certificate = Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT);
                        } catch (CertificateEncodingException e) {
                          e.printStackTrace();
                          showFatalMessageAndQuit("Certificate encoding could not be generated.");
                        }
                        connection.setSshHostKey(certificate);
                        connection.save(database.getWritableDatabase());
                        database.close();
                        // Indicate the certificate was accepted.
                        certificateAccepted = true;
                      }
                    };

                // Generate a sha1 signature of the certificate.
                MessageDigest sha1;
                MessageDigest md5;
                try {
                  sha1 = MessageDigest.getInstance("SHA1");
                  md5 = MessageDigest.getInstance("MD5");
                  sha1.update(cert.getEncoded());
                  Utils.showYesNoPrompt(
                      getContext(),
                      "Continue connecting to " + connection.getAddress() + "?",
                      "The x509 certificate signatures are:"
                          + "\nSHA1:  "
                          + Utils.toHexString(sha1.digest())
                          + "\nMD5:  "
                          + Utils.toHexString(md5.digest())
                          + "\nYou can ensure they are identical to the known signatures of the server certificate to prevent a man-in-the-middle attack.",
                      signatureYes,
                      signatureNo);
                } catch (NoSuchAlgorithmException e2) {
                  e2.printStackTrace();
                  showFatalMessageAndQuit(
                      "Could not generate SHA1 or MD5 signature of certificate. No SHA1/MD5 algorithm found.");
                } catch (CertificateEncodingException e) {
                  e.printStackTrace();
                  showFatalMessageAndQuit("Certificate encoding could not be generated.");
                }
              } else {
                // Compare saved with obtained certificate and quit if they don't match.
                try {
                  if (!connection
                      .getSshHostKey()
                      .equals(Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT))) {
                    showFatalMessageAndQuit(
                        "ERROR: The saved x509 certificate does not match the current server certificate! "
                            + "This could be a man-in-the-middle attack. If you are aware of the key change, delete and recreate the connection.");
                  } else {
                    // In case we need to display information about the certificate, we can
                    // reconstruct it like this:
                    // CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
                    // ByteArrayInputStream in = new
                    // ByteArrayInputStream(Base64.decode(connection.getSshHostKey(),
                    // Base64.DEFAULT));
                    // X509Certificate c = (X509Certificate)certFactory.generateCertificate(in);
                    // android.util.Log.e("  Subject ", c.getSubjectDN().toString());
                    // android.util.Log.e("   Issuer  ", c.getIssuerDN().toString());
                    // The certificate matches, so we proceed.
                    certificateAccepted = true;
                  }
                } catch (CertificateEncodingException e) {
                  e.printStackTrace();
                  showFatalMessageAndQuit("Certificate encoding could not be generated.");
                }
              }
              break;
          }
        }