diff options
author | Jean Michel-Lemieux | 2003-08-11 19:57:18 +0000 |
---|---|---|
committer | Jean Michel-Lemieux | 2003-08-11 19:57:18 +0000 |
commit | d8c5f1efc046d5ad92b88cae64560f189d661a4b (patch) | |
tree | 78e2ce765b597f9203451e648d3981acaa691f90 | |
parent | 632a8c93bb36e46b27a95a5479714ef597032e36 (diff) | |
download | eclipse.platform.team-d8c5f1efc046d5ad92b88cae64560f189d661a4b.tar.gz eclipse.platform.team-d8c5f1efc046d5ad92b88cae64560f189d661a4b.tar.xz eclipse.platform.team-d8c5f1efc046d5ad92b88cae64560f189d661a4b.zip |
Bug 41161: [Sync View] Can cause CVS client to lock SSH account due to invalid password attemps
4 files changed, 89 insertions, 42 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingInputStream.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingInputStream.java index 8266afa8e..26b61275c 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingInputStream.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingInputStream.java @@ -34,6 +34,7 @@ public class PollingInputStream extends FilterInputStream { private static final boolean DEBUG = Policy.DEBUG_STREAMS; private int numAttempts; private IProgressMonitor monitor; + private boolean cancellable; /** * Creates a new polling input stream. @@ -46,6 +47,7 @@ public class PollingInputStream extends FilterInputStream { super(in); this.numAttempts = numAttempts; this.monitor = monitor; + this.cancellable = true; } /** @@ -72,7 +74,7 @@ public class PollingInputStream extends FilterInputStream { in.close(); return; } catch (InterruptedIOException e) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); if (++attempts == numAttempts) throw new InterruptedIOException(Policy.bind("PollingInputStream.closeTimeout")); //$NON-NLS-1$ if (DEBUG) System.out.println("close retry=" + attempts); //$NON-NLS-1$ @@ -91,7 +93,7 @@ public class PollingInputStream extends FilterInputStream { public int read() throws IOException { int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { return in.read(); } catch (InterruptedIOException e) { @@ -112,7 +114,7 @@ public class PollingInputStream extends FilterInputStream { public int read(byte[] buffer, int off, int len) throws IOException { int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { return in.read(buffer, off, len); } catch (InterruptedIOException e) { @@ -134,7 +136,7 @@ public class PollingInputStream extends FilterInputStream { public long skip(long count) throws IOException { int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { return in.skip(count); } catch (InterruptedIOException e) { @@ -159,4 +161,28 @@ public class PollingInputStream extends FilterInputStream { if (in.read(buffer, 0, available) < 1) break; } } + + /** + * Called to set whether cancellation will be checked by this stream. Turning cancellation checking + * off can be very useful for protecting critical portions of a protocol that shouldn't be interrupted. + * For example, it is often necessary to protect login sequences. + * @param cancellable a flag controlling whether this stream will check for cancellation. + */ + public void setIsCancellable(boolean cancellable) { + this.cancellable = cancellable; + } + + /** + * Checked whether the monitor for this stream has been cancelled. If the cancellable + * flag is <code>false</code> then the monitor is never cancelled. + * @return <code>true</code> if the monitor has been cancelled and <code>false</code> + * otherwise. + */ + private boolean checkCancellation() { + if(cancellable) { + return monitor.isCanceled(); + } else { + return false; + } + } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingOutputStream.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingOutputStream.java index 985357eba..ecbdb8eeb 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingOutputStream.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/streams/PollingOutputStream.java @@ -32,6 +32,7 @@ public class PollingOutputStream extends FilterOutputStream { private static final boolean DEBUG = Policy.DEBUG_STREAMS; private int numAttempts; private IProgressMonitor monitor; + private boolean cancellable; /** * Creates a new polling output stream. @@ -44,6 +45,7 @@ public class PollingOutputStream extends FilterOutputStream { super(out); this.numAttempts = numAttempts; this.monitor = monitor; + this.cancellable = true; } /** @@ -56,7 +58,7 @@ public class PollingOutputStream extends FilterOutputStream { public void write(int b) throws IOException { int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { out.write(b); return; @@ -79,7 +81,7 @@ public class PollingOutputStream extends FilterOutputStream { int count = 0; int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { out.write(buffer, off, len); return; @@ -113,7 +115,7 @@ public class PollingOutputStream extends FilterOutputStream { int count = 0; int attempts = 0; for (;;) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); try { out.flush(); return; @@ -151,7 +153,7 @@ public class PollingOutputStream extends FilterOutputStream { out.close(); return; } catch (InterruptedIOException e) { - if (monitor.isCanceled()) throw new OperationCanceledException(); + if (checkCancellation()) throw new OperationCanceledException(); if (++attempts == numAttempts) throw new InterruptedIOException(Policy.bind("PollingOutputStream.closeTimeout")); //$NON-NLS-1$ if (DEBUG) System.out.println("close retry=" + attempts); //$NON-NLS-1$ @@ -159,4 +161,28 @@ public class PollingOutputStream extends FilterOutputStream { } } } + + /** + * Called to set whether cancellation will be checked by this stream. Turning cancellation checking + * off can be very useful for protecting critical portions of a protocol that shouldn't be interrupted. + * For example, it is often necessary to protect login sequences. + * @param cancellable a flag controlling whether this stream will check for cancellation. + */ + public void setIsCancellable(boolean cancellable) { + this.cancellable = cancellable; + } + + /** + * Checked whether the monitor for this stream has been cancelled. If the cancellable + * flag is <code>false</code> then the monitor is never cancelled. + * @return <code>true</code> if the monitor has been cancelled and <code>false</code> + * otherwise. + */ + private boolean checkCancellation() { + if(cancellable) { + return monitor.isCanceled(); + } else { + return false; + } + } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java index 3b0d60c9c..a5d3bb2c8 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java @@ -108,7 +108,6 @@ public class Session { private int compressionLevel = 0; private List expansions; private Collection /* of ICVSFile */ textTransferOverrideSet = null; - private boolean hasBeenConnected = false; private Map caseMappings; // state need to indicate whether @@ -315,9 +314,10 @@ public class Session { if (connection != null) throw new IllegalStateException(); monitor = Policy.monitorFor(monitor); monitor.beginTask(null, 100); + boolean opened = false; + try { connection = location.openConnection(Policy.subMonitorFor(monitor, 50)); - hasBeenConnected = true; ResponseHandler mtHandler = Request.getResponseHandler("MT"); //$NON-NLS-1$ // accept MT messages for all non-standard server @@ -367,18 +367,15 @@ public class Session { if (CVSProviderPlugin.getPlugin().isDetermineVersionEnabled() && location.getServerPlatform() == CVSRepositoryLocation.UNDETERMINED_PLATFORM) { Command.VERSION.execute(this, location, Policy.subMonitorFor(monitor, 10)); } - } catch (CVSException e) { - // If there is a failure opening, make sure we're closed - if (connection != null) { - hasBeenConnected = false; + opened = true; + } finally { + if (connection != null && ! opened) { try { close(); } catch (CVSException ex) { CVSProviderPlugin.log(ex); } } - throw e; - } finally { monitor.done(); } } @@ -389,16 +386,11 @@ public class Session { * @throws IllegalStateException if the Session is not in the OPEN state */ public void close() throws CVSException { - if (connection == null) { - if (hasBeenConnected) { - throw new IllegalStateException(); - } else { - return; - } + if (connection != null) { + connection.close(); + connection = null; + validRequests = null; } - connection.close(); - connection = null; - validRequests = null; } /** diff --git a/bundles/org.eclipse.team.cvs.ssh/src/org/eclipse/team/internal/ccvs/ssh/Client.java b/bundles/org.eclipse.team.cvs.ssh/src/org/eclipse/team/internal/ccvs/ssh/Client.java index bb1d18dab..440594c5b 100644 --- a/bundles/org.eclipse.team.cvs.ssh/src/org/eclipse/team/internal/ccvs/ssh/Client.java +++ b/bundles/org.eclipse.team.cvs.ssh/src/org/eclipse/team/internal/ccvs/ssh/Client.java @@ -23,6 +23,7 @@ import java.math.BigInteger; import java.net.Socket; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.team.internal.ccvs.core.connection.CVSAuthenticationException; import org.eclipse.team.internal.ccvs.core.util.Util; import org.eclipse.team.internal.core.streams.PollingInputStream; @@ -86,7 +87,7 @@ public class Client { private Socket socket; private InputStream socketIn; - private OutputStream socketOut; + private PollingOutputStream socketOut; private InputStream is; private OutputStream os; private boolean connected = false; @@ -294,16 +295,6 @@ public class Client { } } } -public Client(InputStream socketIn, OutputStream socketOut, String username, String password) { - this.socketIn = socketIn; - this.socketOut = socketOut; - this.username = username; - this.password = password; -} -public Client(InputStream socketIn, OutputStream socketOut, String username, String password, String command) { - this(socketIn, socketOut, username, password); - this.command = command; -} public Client(String host, int port, String username, String password) { this.host = host; this.port = port; @@ -360,7 +351,7 @@ public void connect(IProgressMonitor monitor) throws IOException, CVSAuthenticat // Otherwise, set up the connection try { - + PollingInputStream pollingInputStream = null; // Create the socket (the socket should always be null here) if (socket == null) { try { @@ -375,8 +366,10 @@ public void connect(IProgressMonitor monitor) throws IOException, CVSAuthenticat if (timeout >= 0) { socket.setSoTimeout(1000); } - socketIn = new BufferedInputStream(new PollingInputStream(socket.getInputStream(), - timeout > 0 ? timeout : 1, monitor)); + pollingInputStream = new PollingInputStream(socket.getInputStream(), + timeout > 0 ? timeout : 1, monitor); + socketIn = new BufferedInputStream(pollingInputStream); + socketOut = new PollingOutputStream(new TimeoutOutputStream( socket.getOutputStream(), 8192 /*bufferSize*/, 1000 /*writeTimeout*/, 1000 /*closeTimeout*/), timeout > 0 ? timeout : 1, monitor); @@ -385,6 +378,11 @@ public void connect(IProgressMonitor monitor) throws IOException, CVSAuthenticat // read the ssh server id. The socket creation may of failed if the // server cannot accept our connection request. We don't expect the // socket to be closed at this point. + // Don't allow cancellation during the initial handshake and login since this + // can potentially cause the SSH server to think that it is being hacked and + // disable the account. + socketOut.setIsCancellable(false /* don't allow cancellation */); + pollingInputStream.setIsCancellable(false); StringBuffer buf = new StringBuffer(); int c; while ((c = socketIn.read()) != '\n') { @@ -409,6 +407,9 @@ public void connect(IProgressMonitor monitor) throws IOException, CVSAuthenticat socketOut.flush(); login(); + + socketOut.setIsCancellable(true /* allow cancellation */); + pollingInputStream.setIsCancellable(true); // start a shell and enter interactive session or start by // executing the given command. @@ -420,7 +421,6 @@ public void connect(IProgressMonitor monitor) throws IOException, CVSAuthenticat is = new StandardInputStream(); os = new StandardOutputStream(); - connected = true; // If an exception occurs while connected, make sure we disconnect before passing the exception on } finally { @@ -436,8 +436,11 @@ public void disconnect() throws IOException { } if (connected) { connected = false; - send(SSH_MSG_DISCONNECT, null); - cleanup(); + try { + send(SSH_MSG_DISCONNECT, null); + } finally { + cleanup(); + } } } public InputStream getInputStream() throws IOException { |