diff options
author | Kenny Root <kenny@the-b.org> | 2008-11-10 01:48:15 +0000 |
---|---|---|
committer | Kenny Root <kenny@the-b.org> | 2008-11-10 01:48:15 +0000 |
commit | 91634b9e90b8b6581cf949026734b0bdf20a3026 (patch) | |
tree | 1a6548b59a0d526d3c954abab737c9de4c46054c /src | |
parent | 69accfe08fadf4712ec6e1d38a7f2c7410bcba44 (diff) | |
download | connectbot-91634b9e90b8b6581cf949026734b0bdf20a3026.tar.gz connectbot-91634b9e90b8b6581cf949026734b0bdf20a3026.tar.bz2 connectbot-91634b9e90b8b6581cf949026734b0bdf20a3026.zip |
* Allow user to have a port-forward-only connection to a host (similar to OpenSSH's -N option)
* Fixed bug with adding port forwards
* Fixed bug where we crash if connection goes away while we're initializing the ConsoleActivity
Diffstat (limited to 'src')
-rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 39 | ||||
-rw-r--r-- | src/org/connectbot/PortForwardListActivity.java | 25 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalBridge.java | 93 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalManager.java | 4 | ||||
-rw-r--r-- | src/org/connectbot/util/HostDatabase.java | 42 |
5 files changed, 162 insertions, 41 deletions
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 98ff46c..1204669 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -133,9 +133,14 @@ public class ConsoleActivity extends Activity { } - // show the requested bridge if found, also fade out overlay - flip.setDisplayedChild(requestedIndex); - flip.getCurrentView().findViewById(R.id.terminal_overlay).startAnimation(fade_out); + try { + // show the requested bridge if found, also fade out overlay + flip.setDisplayedChild(requestedIndex); + flip.getCurrentView().findViewById(R.id.terminal_overlay).startAnimation(fade_out); + } catch (NullPointerException npe) { + Log.d(TAG, "View went away when we were about to display it", npe); + } + updatePromptVisible(); updateEmptyVisible(); @@ -608,8 +613,11 @@ public class ConsoleActivity extends Activity { final View view = findCurrentView(R.id.console_flip); boolean activeTerminal = (view instanceof TerminalView); boolean authenticated = false; - if(activeTerminal) - authenticated = ((TerminalView)view).bridge.fullyConnected; + boolean sessionOpen = false; + if(activeTerminal) { + authenticated = ((TerminalView) view).bridge.isAuthenticated(); + sessionOpen = ((TerminalView)view).bridge.isSessionOpen(); + } disconnect = menu.add(R.string.console_menu_disconnect); disconnect.setEnabled(activeTerminal); @@ -628,7 +636,7 @@ public class ConsoleActivity extends Activity { copy = menu.add(R.string.console_menu_copy); copy.setIcon(android.R.drawable.ic_menu_set_as); - copy.setEnabled(activeTerminal && authenticated); + copy.setEnabled(activeTerminal); copy.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { // mark as copying and reset any previous bounds @@ -661,7 +669,7 @@ public class ConsoleActivity extends Activity { portForward = menu.add(R.string.console_menu_portforwards); portForward.setIcon(android.R.drawable.ic_menu_manage); - portForward.setEnabled(activeTerminal && authenticated); + portForward.setEnabled(authenticated); portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { Intent intent = new Intent(ConsoleActivity.this, PortForwardListActivity.class); @@ -673,7 +681,7 @@ public class ConsoleActivity extends Activity { resize = menu.add(R.string.console_menu_resize); resize.setIcon(android.R.drawable.ic_menu_crop); - resize.setEnabled(activeTerminal && authenticated); + resize.setEnabled(activeTerminal && sessionOpen); resize.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { final TerminalView terminal = (TerminalView)view; @@ -724,14 +732,17 @@ public class ConsoleActivity extends Activity { final View view = findCurrentView(R.id.console_flip); boolean activeTerminal = (view instanceof TerminalView); boolean authenticated = false; - if(activeTerminal) - authenticated = ((TerminalView)view).bridge.fullyConnected; - + boolean sessionOpen = false; + if (activeTerminal) { + authenticated = ((TerminalView)view).bridge.isAuthenticated(); + sessionOpen = ((TerminalView)view).bridge.isSessionOpen(); + } + disconnect.setEnabled(activeTerminal); - copy.setEnabled(activeTerminal && authenticated); - paste.setEnabled(clipboard.hasText() && activeTerminal && authenticated); + copy.setEnabled(activeTerminal); + paste.setEnabled(clipboard.hasText() && activeTerminal && sessionOpen); portForward.setEnabled(activeTerminal && authenticated); - resize.setEnabled(activeTerminal && authenticated); + resize.setEnabled(activeTerminal && sessionOpen); return true; } diff --git a/src/org/connectbot/PortForwardListActivity.java b/src/org/connectbot/PortForwardListActivity.java index c5d4cb5..e2097fa 100644 --- a/src/org/connectbot/PortForwardListActivity.java +++ b/src/org/connectbot/PortForwardListActivity.java @@ -168,7 +168,18 @@ public class PortForwardListActivity extends ListActivity { public boolean onMenuItemClick(MenuItem item) { // build dialog to prompt user about updating final View portForwardView = inflater.inflate(R.layout.dia_portforward, null, false); + final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination); final Spinner typeSpinner = (Spinner)portForwardView.findViewById(R.id.portforward_type); + + typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { + public void onItemSelected(AdapterView<?> value, View view, + int position, long id) { + destEdit.setEnabled(position != 2); + } + public void onNothingSelected(AdapterView<?> arg0) { + } + }); + new AlertDialog.Builder(PortForwardListActivity.this) .setView(portForwardView) .setPositiveButton(R.string.portforward_pos, new DialogInterface.OnClickListener() { @@ -176,9 +187,19 @@ public class PortForwardListActivity extends ListActivity { try { final EditText nicknameEdit = (EditText) portForwardView.findViewById(R.id.nickname); final EditText sourcePortEdit = (EditText) portForwardView.findViewById(R.id.portforward_source); - final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination); - String type = (String)typeSpinner.getSelectedItem(); + String type = HostDatabase.PORTFORWARD_LOCAL; + switch (typeSpinner.getSelectedItemPosition()) { + case 0: + type = HostDatabase.PORTFORWARD_LOCAL; + break; + case 1: + type = HostDatabase.PORTFORWARD_REMOTE; + break; + case 2: + type = HostDatabase.PORTFORWARD_DYNAMIC5; + break; + } PortForwardBean pfb = new PortForwardBean(hostId, nicknameEdit.getText().toString(), type, diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 1762262..4cb1b2b 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -109,6 +109,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal public final String nickname; protected final String username; public String postlogin = null; + private boolean wantSession = true; public final Connection connection; protected Session session; @@ -145,6 +146,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal // read in all known hosts from hostdb KnownHosts hosts = manager.hostdb.getKnownHosts(); + Boolean result; switch(hosts.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey)) { case KnownHosts.HOSTKEY_IS_OK: @@ -154,9 +156,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal // prompt user outputLine(String.format("The authenticity of host '%s' can't be established.", hostname)); outputLine(String.format("RSA key fingerprint is %s", KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey))); - //outputLine("[For now we'll assume you accept this key, but tap Menu and Disconnect if not.]"); - //outputLine("Are you sure you want to continue connecting (yes/no)? "); - Boolean result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?"); + + result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?"); if(result == null) return false; if(result.booleanValue()) { // save this key in known database @@ -172,9 +173,15 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal outputLine("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); outputLine("It is also possible that the RSA host key has just been changed."); outputLine(String.format("RSA key fingerprint is %s", KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey))); - outputLine("Host key verification failed."); - return false; + // Users have no way to delete keys, so we'll prompt them for now. + result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?"); + if(result == null) return false; + if(result.booleanValue()) { + // save this key in known database + manager.hostdb.saveKnownHost(hostname, serverHostKeyAlgorithm, serverHostKey); + } + return result.booleanValue(); } return false; @@ -184,7 +191,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } public PromptHelper promptHelper; - + /** * Create new terminal bridge with following parameters. We will immediately * launch thread to start SSH connection and handle any hostkey verification @@ -199,6 +206,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal this.emulation = manager.getEmulation(); this.scrollback = manager.getScrollback(); this.postlogin = manager.getPostLogin(nickname); + this.wantSession = manager.getWantSession(nickname); // create prompt helper to relay password and hostkey requests up to gui this.promptHelper = new PromptHelper(this); @@ -260,7 +268,12 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal public void run() { try { connection.connect(new HostKeyVerifier()); - + } catch (IOException e) { + Log.e(TAG, "Problem in SSH connection thread during authentication", e); + Log.d(TAG, String.format("Cause is: %s", e.getCause().toString())); + } + + try { // enter a loop to keep trying until authentication int tries = 0; while(!connection.isAuthenticationComplete() && tries++ < AUTH_TRIES && !disconnectFlag) { @@ -270,7 +283,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal Thread.sleep(1000); } } catch(Exception e) { - Log.e(TAG, "Problem in SSH connection thread", e); + Log.e(TAG, "Problem in SSH connection thread during authentication", e); } } }).start(); @@ -466,13 +479,30 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal }).start(); } - public boolean fullyConnected = false; + private boolean authenticated = false; + private boolean sessionOpen = false; /** * Internal method to request actual PTY terminal once we've finished * authentication. If called before authenticated, it will just fail. */ protected void finishConnection() { + setAuthenticated(true); + + // Start up predefined port forwards + for (PortForwardBean pfb : portForwards) { + try { + enablePortForward(pfb); + outputLine(String.format("Enable port forward: %s", pfb.getDescription())); + } catch (Exception e) { + Log.e(TAG, "Error setting up port forward during connect", e); + } + } + + if (!wantSession) { + outputLine("Session will not be started due to host preference."); + return; + } try { this.session = connection.openSession(); @@ -508,21 +538,15 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } } }); - this.relay.start(); + relay.start(); // force font-size to make sure we resizePTY as needed - this.setFontSize(this.fontSize); + setFontSize(this.fontSize); - this.fullyConnected = true; - - // Start up predefined port forwards - for (PortForwardBean pfb : portForwards) { - enablePortForward(pfb); - Log.d(TAG, String.format("Enabling port formard %s (enabled? %b)", pfb.getDescription(), pfb.isEnabled())); - } + setSessionOpen(true); // finally send any post-login string, if requested - this.injectString(postlogin); + injectString(postlogin); } catch (IOException e1) { Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1); @@ -530,6 +554,20 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } + /** + * @param sessionOpen the sessionOpen to set + */ + public void setSessionOpen(boolean sessionOpen) { + this.sessionOpen = sessionOpen; + } + + /** + * @return the sessionOpen + */ + public boolean isSessionOpen() { + return sessionOpen; + } + protected BridgeDisconnectedListener disconnectListener = null; public void setOnDisconnectedListener(BridgeDisconnectedListener disconnectListener) { @@ -553,7 +591,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal }).start(); this.disconnectFlag = true; - this.fullyConnected = false; + this.authenticated = false; + this.sessionOpen = false; // pass notification back up to terminal manager // the manager will do any gui notification if applicable @@ -1145,4 +1184,18 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal return false; } } + + /** + * @param authenticated the authenticated to set + */ + public void setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + } + + /** + * @return the authenticated + */ + public boolean isAuthenticated() { + return authenticated; + } } diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java index 336d1fa..a0753df 100644 --- a/src/org/connectbot/service/TerminalManager.java +++ b/src/org/connectbot/service/TerminalManager.java @@ -167,6 +167,10 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen return hostdb.getPostLogin(nickname); } + public boolean getWantSession(String nickname) { + return hostdb.getWantSession(nickname); + } + public String getKeyMode() { return prefs.getString(this.pref_keymode, getString(R.string.list_keymode_right)); // "Use right-side keys" } diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java index dd003fe..c98fcce 100644 --- a/src/org/connectbot/util/HostDatabase.java +++ b/src/org/connectbot/util/HostDatabase.java @@ -43,7 +43,7 @@ public class HostDatabase extends SQLiteOpenHelper { public final static String TAG = HostDatabase.class.toString(); public final static String DB_NAME = "hosts"; - public final static int DB_VERSION = 12; + public final static int DB_VERSION = 13; public final static String TABLE_HOSTS = "hosts"; public final static String FIELD_HOST_NICKNAME = "nickname"; @@ -57,6 +57,7 @@ public class HostDatabase extends SQLiteOpenHelper { public final static String FIELD_HOST_USEKEYS = "usekeys"; public final static String FIELD_HOST_POSTLOGIN = "postlogin"; public final static String FIELD_HOST_PUBKEYID = "pubkeyid"; + public final static String FIELD_HOST_WANTSESSION = "wantsession"; public final static String TABLE_PORTFORWARDS = "portforwards"; public final static String FIELD_PORTFORWARD_HOSTID = "hostid"; @@ -97,7 +98,8 @@ public class HostDatabase extends SQLiteOpenHelper { + FIELD_HOST_COLOR + " TEXT, " + FIELD_HOST_USEKEYS + " TEXT, " + FIELD_HOST_POSTLOGIN + " TEXT, " - + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ")"); + + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", " + + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "')"); // insert a few sample hosts, none of which probably connect //this.createHost(db, "connectbot@bravo", "connectbot", "192.168.254.230", 22, COLOR_GRAY); @@ -136,7 +138,10 @@ public class HostDatabase extends SQLiteOpenHelper { + FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", " + FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, " + FIELD_PORTFORWARD_DESTADDR + " TEXT, " - + FIELD_PORTFORWARD_DESTPORT + " INTEGER)"); + + FIELD_PORTFORWARD_DESTPORT + " INTEGER)"); + case 12: + db.execSQL("ALTER TABLE " + TABLE_HOSTS + + " ADD COLUMN " + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "'"); } } @@ -219,6 +224,7 @@ public class HostDatabase extends SQLiteOpenHelper { if(color != null) values.put(FIELD_HOST_COLOR, color); values.put(FIELD_HOST_PUBKEYID, pubkeyId); + values.put(FIELD_HOST_WANTSESSION, Boolean.toString(true)); return db.insert(TABLE_HOSTS, null, values); @@ -254,19 +260,45 @@ public class HostDatabase extends SQLiteOpenHelper { * Find the post-login command string for the given nickname. */ public String getPostLogin(String nickname) { - String result = null; + SQLiteDatabase db = this.getReadableDatabase(); Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_POSTLOGIN }, FIELD_HOST_NICKNAME + " = ?", new String[] { nickname }, null, null, null); - if(c == null || !c.moveToFirst()) { + + if (c == null || !c.moveToFirst()) { result = null; } else { result = c.getString(c.getColumnIndexOrThrow(FIELD_HOST_POSTLOGIN)); } + c.close(); + db.close(); + return result; + } + + /** + * Check whether a host should have a shell session started. + * @param nickname Nick name of host to check + * @return true if host should have a shell session started + */ + public boolean getWantSession(String nickname) { + Boolean result = true; + SQLiteDatabase db = this.getReadableDatabase(); + Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_WANTSESSION }, + FIELD_HOST_NICKNAME + " = ?", new String[] { nickname }, null, null, null); + if(c == null || !c.moveToFirst()) { + result = true; + } else { + result = Boolean.valueOf(c.getString(c.getColumnIndexOrThrow(FIELD_HOST_WANTSESSION))); + } + + c.close(); + db.close(); + + return result; } /** |