sshclient.java
来自「一个非常好的ssh客户端实现」· Java 代码 · 共 1,227 行 · 第 1/3 页
JAVA
1,227 行
outpdu.writeInt(pubKey.getModulus().bitLength()); outpdu.writeBigInteger(pubKey.getPublicExponent()); outpdu.writeBigInteger(pubKey.getModulus()); } else { outpdu = new SSHPduOutputStream(CMSG_AUTH_RSA, sndCipher, sndComp, rand); outpdu.writeBigInteger(pubKey.getModulus()); } outpdu.writeTo(sshOut); SSHPduInputStream inpdu = new SSHPduInputStream(MSG_ANY, rcvCipher, rcvComp); inpdu.readFrom(sshIn); if(inpdu.type == SMSG_FAILURE) throw new AuthFailException("server refused our key" + (rhosts ? " or rhosts" : "")); else if(inpdu.type != SMSG_AUTH_RSA_CHALLENGE) throw new IOException("Protocol error, expected RSA-challenge but got " + inpdu.type); BigInteger challenge = inpdu.readBigInteger(); // First try with an empty passphrase... // RSAPrivateCrtKey privKey = keyFile.getPrivate(""); if(privKey == null) privKey = keyFile.getPrivate(authenticator.getIdentityPassword(user)); else if(interactor != null) interactor.report("Authenticated with password-less rsa-key '" + keyFile.getComment() + "'"); if(privKey == null) throw new AuthFailException("invalid password for key-file '" + keyFile.getComment() + "'"); rsaChallengeResponse(privKey, challenge); } private final static int CANNOT_CHOOSE_PIN = 0; private final static int USER_SELECTABLE = 1; private final static int MUST_CHOOSE_PIN = 2; void doSDIAuth(String userName) throws IOException { SSHPduOutputStream outpdu; String password; password = authenticator.getChallengeResponse(user, userName + "'s SDI token passcode: "); outpdu = new SSHPduOutputStream(CMSG_AUTH_SDI, sndCipher, sndComp, rand); outpdu.writeString(password); outpdu.writeTo(sshOut); SSHPduInputStream inpdu = new SSHPduInputStream(MSG_ANY, rcvCipher, rcvComp); inpdu.readFrom(sshIn); switch(inpdu.type) { case SMSG_SUCCESS: interactor.report("SDI authentication accepted."); break; case SMSG_FAILURE: throw new AuthFailException("SDI authentication failed."); case CMSG_ACM_NEXT_CODE_REQUIRED: password = interactor.promptPassword("Next token required: "); outpdu = new SSHPduOutputStream(CMSG_ACM_NEXT_CODE, sndCipher, sndComp, rand); outpdu.writeString(password); outpdu.writeTo(sshOut); if(!isSuccess()) throw new AuthFailException(); break; case CMSG_ACM_NEW_PIN_REQUIRED: if(!interactor.askConfirmation("New PIN required, do you want to continue?", false)) throw new AuthFailException("new PIN not wanted"); String type = inpdu.readString(); String size = inpdu.readString(); int userSelect = inpdu.readInt(); switch(userSelect) { case CANNOT_CHOOSE_PIN: break; case USER_SELECTABLE: case MUST_CHOOSE_PIN: String pwdChk; do { password = interactor.promptPassword("Please enter new PIN" + " containing " + size + " " + type); pwdChk = interactor.promptPassword("Please enter new PIN again"); } while (!password.equals(pwdChk)); outpdu = new SSHPduOutputStream(CMSG_ACM_NEW_PIN, sndCipher, sndComp, rand); outpdu.writeString(password); outpdu.writeTo(sshOut); inpdu = new SSHPduInputStream(MSG_ANY, rcvCipher, rcvComp); inpdu.readFrom(sshIn); if(inpdu.type != CMSG_ACM_NEW_PIN_ACCEPTED) { throw new AuthFailException("PIN rejected by server"); } throw new AuthFailException("new PIN accepted, " + "wait for the code on your token to change"); default: throw new AuthFailException("invalid response from server"); } break; case CMSG_ACM_ACCESS_DENIED: // Fall through default: throw new AuthFailException(); } } void rsaChallengeResponse(RSAPrivateCrtKey privKey, BigInteger challenge) throws IOException { MessageDigest md5; try { challenge = RSAAlgorithm.doPrivateCrt(challenge, privKey.getPrimeP(), privKey.getPrimeQ(), privKey.getPrimeExponentP(), privKey.getPrimeExponentQ(), privKey.getCrtCoefficient()); challenge = RSAAlgorithm.stripPKCS1Pad(challenge, 2); } catch(Exception e) { throw new IOException(e.getMessage()); } byte[] response = challenge.toByteArray(); try { md5 = MessageDigest.getInstance("MD5"); if(response[0] == 0) md5.update(response, 1, 32); else md5.update(response, 0, 32); md5.update(sessionId); response = md5.digest(); } catch(Exception e) { throw new IOException("MD5 not implemented, can't generate session-id"); } SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_AUTH_RSA_RESPONSE, sndCipher, sndComp, rand); outpdu.write(response, 0, response.length); outpdu.writeTo(sshOut); if(!isSuccess()) throw new AuthFailException(); } void initiateSession() throws IOException { if(user.wantPTY()) requestPTY(); int maxPktSz = user.getMaxPacketSz(); if(maxPktSz > 0) requestMaxPacketSz(maxPktSz); if(user.wantX11Forward()) requestX11Forward(); if(activateTunnels) initiateTunnels(); if(commandLine != null) requestCommand(commandLine); else requestShell(); // !!! // At this stage we can't send more options/forward-requests // the server has now entered it's service-loop. } void initiatePlugins() { SSHProtocolPlugin.initiateAll(this); } void initiateTunnels() throws IOException { int i; for(i = 0; i < localForwards.size(); i++) { LocalForward fwd = (LocalForward) localForwards.elementAt(i); requestLocalPortForward(fwd.localHost, fwd.localPort, fwd.remoteHost, fwd.remotePort, fwd.plugin); } for(i = 0; i < remoteForwards.size(); i++) { RemoteForward fwd = (RemoteForward) remoteForwards.elementAt(i); requestRemotePortForward(fwd.remotePort, fwd.localHost, fwd.localPort, fwd.plugin); } } void requestCompression(int level) throws IOException { if(level == 0) { return; } SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_REQUEST_COMPRESSION, sndCipher, sndComp, rand); outpdu.writeInt(level); outpdu.writeTo(sshOut); if(!isSuccess() && interactor != null) interactor.report("Error requesting compression level: " + level); sndComp = SSHCompressor.getInstance("zlib", SSHCompressor.COMPRESS_MODE, level); rcvComp = SSHCompressor.getInstance("zlib", SSHCompressor.UNCOMPRESS_MODE, level); } void requestMaxPacketSz(int sz) throws IOException { SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_MAX_PACKET_SIZE, sndCipher, sndComp, rand); outpdu.writeInt(sz); outpdu.writeTo(sshOut); if(!isSuccess() && interactor != null) interactor.report("Error requesting max packet size: " + sz); } void requestX11Forward() throws IOException { SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_X11_REQUEST_FORWARDING, sndCipher, sndComp, rand); // !!! outpdu.writeString("MIT-MAGIC-COOKIE-1"); outpdu.writeString("112233445566778899aabbccddeeff00"); outpdu.writeInt(0); // !!! outpdu.writeTo(sshOut); if(!isSuccess() && interactor != null) interactor.report("Error requesting X11 forward"); } void requestPTY() throws IOException { SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_REQUEST_PTY, sndCipher, sndComp, rand); Terminal myTerminal = null; if(console != null) myTerminal = console.getTerminal(); if(myTerminal != null) { outpdu.writeString(myTerminal.terminalType()); outpdu.writeInt(myTerminal.rows()); outpdu.writeInt(myTerminal.cols()); outpdu.writeInt(myTerminal.vpixels()); outpdu.writeInt(myTerminal.hpixels()); } else { outpdu.writeString(""); outpdu.writeInt(0); outpdu.writeInt(0); outpdu.writeInt(0); outpdu.writeInt(0); } outpdu.writeByte((byte)TTY_OP_END); outpdu.writeTo(sshOut); if(!isSuccess() && interactor != null) interactor.report("Error requesting PTY"); } void requestLocalPortForward(String localHost, int localPort, String remoteHost, int remotePort, String plugin) throws IOException { controller.newListenChannel(localHost, localPort, remoteHost, remotePort, plugin); } void requestRemotePortForward(int remotePort, String localHost, int localPort, String plugin) throws IOException { try { SSHProtocolPlugin.getPlugin(plugin).remoteListener(remotePort, localHost, localPort, controller); } catch (NoClassDefFoundError e) { throw new IOException("Plugins not available"); } SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_PORT_FORWARD_REQUEST, sndCipher, sndComp, rand); outpdu.writeInt(remotePort); outpdu.writeString(localHost); outpdu.writeInt(localPort); outpdu.writeTo(sshOut); if(!isSuccess() && interactor != null) { interactor.report("Error requesting remote port forward: " + plugin + "/" + remotePort + ":" + localHost + ":" + localPort); } } void requestCommand(String command) throws IOException { SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_EXEC_CMD, sndCipher, sndComp, rand); outpdu.writeString(command); outpdu.writeTo(sshOut); } void requestShell() throws IOException { SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_EXEC_SHELL, sndCipher, sndComp, rand); outpdu.writeTo(sshOut); } boolean isSuccess() throws IOException { boolean success = false; SSHPduInputStream inpdu = null; inpdu = new SSHPduInputStream(MSG_ANY, rcvCipher, rcvComp); inpdu.readFrom(sshIn); if(inpdu.type == SMSG_SUCCESS) success = true; else if(inpdu.type == SMSG_FAILURE) success = false; else if(inpdu.type == MSG_DISCONNECT) throw new IOException("Server disconnected: " + inpdu.readString()); else throw new IOException("Protocol error: got " + inpdu.type + " when expecting success/failure"); return success; } void setInteractive() { try { sshSocket.setTcpNoDelay(true); } catch (SocketException e) { if(interactor != null) interactor.report("Error setting interactive mode: " + e.getMessage()); } } void setAliveInterval(int i) { if(i == 0) { if(keepAliveThread != null && keepAliveThread.isAlive()) keepAliveThread.stop(); keepAliveThread = null; } else { if(keepAliveThread != null) { keepAliveThread.setInterval(i); } else { keepAliveThread = new KeepAliveThread(i); keepAliveThread.setDaemon(true); keepAliveThread.start(); } } } public boolean isOpened() { return isOpened; } public boolean isConnected() { return isConnected; } void stdinWriteChar(char c) throws IOException { stdinWriteString(String.valueOf(c)); } void stdinWriteString(String str) throws IOException { stdinWriteString(str.getBytes(), 0, str.length()); } void stdinWriteString(byte[] str) throws IOException { stdinWriteString(str, 0, str.length); } void stdinWriteString(byte[] str, int off, int len) throws IOException { SSHPduOutputStream stdinPdu; if(isOpened && controller != null) { stdinPdu = new SSHPduOutputStream(SSH.CMSG_STDIN_DATA, sndCipher, sndComp, rand); stdinPdu.writeInt(len); stdinPdu.write(str, off, len); controller.transmit(stdinPdu); } } void signalWindowChanged(int rows, int cols, int vpixels, int hpixels) { if(isOpened && controller != null) { try { SSHPduOutputStream pdu; pdu = new SSHPduOutputStream(SSH.CMSG_WINDOW_SIZE, sndCipher, sndComp, rand); pdu.writeInt(rows); pdu.writeInt(cols); pdu.writeInt(vpixels); pdu.writeInt(hpixels); controller.transmit(pdu); } catch (Exception ex) { if(interactor != null) interactor.alert("Error when sending sigWinch: " + ex.toString()); } } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?