Mercurial > 510Connectbot
comparison src/com/five_ten_sg/connectbot/transport/SSH.java @ 31:139394237973 tn5250
start tn5250 integration
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 10 Jun 2014 12:00:07 -0700 |
parents | 6aaefb22d876 |
children | 77ac18bc1b2f |
comparison
equal
deleted
inserted
replaced
30:d738f6b876fe | 31:139394237973 |
---|---|
80 /** | 80 /** |
81 * @author Kenny Root | 81 * @author Kenny Root |
82 * | 82 * |
83 */ | 83 */ |
84 public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveCallback, AuthAgentCallback { | 84 public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveCallback, AuthAgentCallback { |
85 public SSH() { | |
86 super(); | |
87 } | |
88 | |
89 /** | |
90 * @param host | |
91 * @param bridge | |
92 * @param manager | |
93 */ | |
94 public SSH(HostBean host, TerminalBridge bridge, TerminalManager manager) { | |
95 super(host, bridge, manager); | |
96 } | |
97 | |
98 private static final String PROTOCOL = "ssh"; | 85 private static final String PROTOCOL = "ssh"; |
99 private static final String TAG = "ConnectBot.SSH"; | 86 private static final String TAG = "ConnectBot.SSH"; |
100 private static final int DEFAULT_PORT = 22; | 87 private static final int DEFAULT_PORT = 22; |
101 | 88 |
102 private static final String AUTH_PUBLICKEY = "publickey", | 89 private static final String AUTH_PUBLICKEY = "publickey", |
210 } | 197 } |
211 } | 198 } |
212 | 199 |
213 } | 200 } |
214 | 201 |
202 | |
203 public SSH() { | |
204 super(); | |
205 } | |
206 | |
207 | |
208 /** | |
209 * @return protocol part of the URI | |
210 */ | |
211 public static String getProtocolName() { | |
212 return PROTOCOL; | |
213 } | |
214 | |
215 | |
216 public Uri getUri(String input) { | |
217 Matcher matcher = hostmask.matcher(input); | |
218 | |
219 if (!matcher.matches()) | |
220 return null; | |
221 | |
222 StringBuilder sb = new StringBuilder(); | |
223 sb.append(PROTOCOL) | |
224 .append("://") | |
225 .append(Uri.encode(matcher.group(1))) | |
226 .append('@') | |
227 .append(matcher.group(2)); | |
228 String portString = matcher.group(4); | |
229 int port = DEFAULT_PORT; | |
230 | |
231 if (portString != null) { | |
232 try { | |
233 port = Integer.parseInt(portString); | |
234 | |
235 if (port < 1 || port > 65535) { | |
236 port = DEFAULT_PORT; | |
237 } | |
238 } | |
239 catch (NumberFormatException nfe) { | |
240 // Keep the default port | |
241 } | |
242 } | |
243 | |
244 if (port != DEFAULT_PORT) { | |
245 sb.append(':') | |
246 .append(port); | |
247 } | |
248 | |
249 sb.append("/#") | |
250 .append(Uri.encode(input)); | |
251 Uri uri = Uri.parse(sb.toString()); | |
252 return uri; | |
253 } | |
254 | |
255 | |
215 private void authenticate() { | 256 private void authenticate() { |
216 try { | 257 try { |
217 if (connection.authenticateWithNone(host.getUsername())) { | 258 if (connection.authenticateWithNone(host.getUsername())) { |
218 finishConnection(); | 259 finishConnection(); |
219 return; | 260 return; |
300 } | 341 } |
301 catch (Exception e) { | 342 catch (Exception e) { |
302 Log.e(TAG, "Problem during handleAuthentication()", e); | 343 Log.e(TAG, "Problem during handleAuthentication()", e); |
303 } | 344 } |
304 } | 345 } |
346 | |
305 | 347 |
306 /** | 348 /** |
307 * Attempt connection with database row pointed to by cursor. | 349 * Attempt connection with database row pointed to by cursor. |
308 * @param cursor | 350 * @param cursor |
309 * @return true for successful authentication | 351 * @return true for successful authentication |
369 } | 411 } |
370 | 412 |
371 return tryPublicKey(host.getUsername(), pubkey.getNickname(), pair); | 413 return tryPublicKey(host.getUsername(), pubkey.getNickname(), pair); |
372 } | 414 } |
373 | 415 |
416 | |
374 private boolean tryPublicKey(String username, String keyNickname, KeyPair pair) throws IOException { | 417 private boolean tryPublicKey(String username, String keyNickname, KeyPair pair) throws IOException { |
375 //bridge.outputLine(String.format("Attempting 'publickey' with key '%s' [%s]...", keyNickname, trileadKey.toString())); | 418 //bridge.outputLine(String.format("Attempting 'publickey' with key '%s' [%s]...", keyNickname, trileadKey.toString())); |
376 boolean success = connection.authenticateWithPublicKey(username, pair); | 419 boolean success = connection.authenticateWithPublicKey(username, pair); |
377 | 420 |
378 if (!success) | 421 if (!success) |
379 bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_fail, keyNickname)); | 422 bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_fail, keyNickname)); |
380 | 423 |
381 return success; | 424 return success; |
382 } | 425 } |
426 | |
383 | 427 |
384 /** | 428 /** |
385 * Internal method to request actual PTY terminal once we've finished | 429 * Internal method to request actual PTY terminal once we've finished |
386 * authentication. If called before authenticated, it will just fail. | 430 * authentication. If called before authenticated, it will just fail. |
387 */ | 431 */ |
429 } | 473 } |
430 catch (IOException e1) { | 474 catch (IOException e1) { |
431 Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1); | 475 Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1); |
432 } | 476 } |
433 } | 477 } |
478 | |
434 | 479 |
435 @Override | 480 @Override |
436 public void connect() { | 481 public void connect() { |
437 connection = new Connection(host.getHostname(), host.getPort()); | 482 connection = new Connection(host.getHostname(), host.getPort()); |
438 connection.addConnectionMonitor(this); | 483 connection.addConnectionMonitor(this); |
535 catch (Exception e) { | 580 catch (Exception e) { |
536 Log.e(TAG, "Problem in SSH connection thread during authentication", e); | 581 Log.e(TAG, "Problem in SSH connection thread during authentication", e); |
537 } | 582 } |
538 } | 583 } |
539 | 584 |
540 @Override | |
541 public void close() { | |
542 connected = false; | |
543 | |
544 if (session != null) { | |
545 session.close(); | |
546 session = null; | |
547 } | |
548 | |
549 if (connection != null) { | |
550 connection.close(); | |
551 connection = null; | |
552 } | |
553 } | |
554 | |
555 private void onDisconnect() { | |
556 close(); | |
557 bridge.dispatchDisconnect(false); | |
558 } | |
559 | |
560 @Override | |
561 public void flush() throws IOException { | |
562 if (stdin != null) | |
563 stdin.flush(); | |
564 } | |
565 | 585 |
566 @Override | 586 @Override |
567 public boolean willBlock() { | 587 public boolean willBlock() { |
568 if (stdout == null) return true; | 588 if (stdout == null) return true; |
569 try { | 589 try { |
571 } catch (Exception e) { | 591 } catch (Exception e) { |
572 return true; | 592 return true; |
573 } | 593 } |
574 } | 594 } |
575 | 595 |
596 | |
576 @Override | 597 @Override |
577 public int read(byte[] buffer, int start, int len) throws IOException { | 598 public int read(byte[] buffer, int start, int len) throws IOException { |
578 int bytesRead = 0; | 599 int bytesRead = 0; |
579 | 600 |
580 if (session == null) | 601 if (session == null) |
600 } | 621 } |
601 | 622 |
602 return bytesRead; | 623 return bytesRead; |
603 } | 624 } |
604 | 625 |
626 | |
605 @Override | 627 @Override |
606 public void write(byte[] buffer) throws IOException { | 628 public void write(byte[] buffer) throws IOException { |
607 if (stdin != null) | 629 if (stdin != null) |
608 stdin.write(buffer); | 630 stdin.write(buffer); |
609 } | 631 } |
610 | 632 |
633 | |
611 @Override | 634 @Override |
612 public void write(int c) throws IOException { | 635 public void write(int c) throws IOException { |
613 if (stdin != null) | 636 if (stdin != null) |
614 stdin.write(c); | 637 stdin.write(c); |
615 } | 638 } |
616 | 639 |
640 | |
641 @Override | |
642 public void flush() throws IOException { | |
643 if (stdin != null) | |
644 stdin.flush(); | |
645 } | |
646 | |
647 | |
648 public void connectionLost(Throwable reason) { | |
649 onDisconnect(); | |
650 } | |
651 | |
652 | |
653 private void onDisconnect() { | |
654 close(); | |
655 bridge.dispatchDisconnect(false); | |
656 } | |
657 | |
658 | |
659 @Override | |
660 public void close() { | |
661 connected = false; | |
662 | |
663 if (session != null) { | |
664 session.close(); | |
665 session = null; | |
666 } | |
667 | |
668 if (connection != null) { | |
669 connection.close(); | |
670 connection = null; | |
671 } | |
672 } | |
673 | |
674 | |
675 @Override | |
676 public void setDimensions(int columns, int rows, int width, int height) { | |
677 this.columns = columns; | |
678 this.rows = rows; | |
679 | |
680 if (sessionOpen) { | |
681 try { | |
682 session.resizePTY(columns, rows, width, height); | |
683 } | |
684 catch (IOException e) { | |
685 Log.e(TAG, "Couldn't send resize PTY packet", e); | |
686 } | |
687 } | |
688 } | |
689 | |
690 | |
691 @Override | |
692 public void setOptions(Map<String, String> options) { | |
693 if (options.containsKey("compression")) | |
694 compression = Boolean.parseBoolean(options.get("compression")); | |
695 | |
696 if (options.containsKey("httpproxy")) | |
697 httpproxy = options.get("httpproxy"); | |
698 } | |
699 | |
700 | |
617 @Override | 701 @Override |
618 public Map<String, String> getOptions() { | 702 public Map<String, String> getOptions() { |
619 Map<String, String> options = new HashMap<String, String>(); | 703 Map<String, String> options = new HashMap<String, String>(); |
620 options.put("compression", Boolean.toString(compression)); | 704 options.put("compression", Boolean.toString(compression)); |
621 | 705 |
623 options.put("httpproxy", httpproxy); | 707 options.put("httpproxy", httpproxy); |
624 | 708 |
625 return options; | 709 return options; |
626 } | 710 } |
627 | 711 |
628 @Override | 712 |
629 public void setOptions(Map<String, String> options) { | 713 @Override |
630 if (options.containsKey("compression")) | 714 public void setCompression(boolean compression) { |
631 compression = Boolean.parseBoolean(options.get("compression")); | 715 this.compression = compression; |
632 | 716 } |
633 if (options.containsKey("httpproxy")) | 717 |
634 httpproxy = options.get("httpproxy"); | 718 |
635 } | 719 @Override |
636 | 720 public void setHttpproxy(String httpproxy) { |
637 /** | 721 this.httpproxy = httpproxy; |
638 * @return protocol part of the URI | 722 } |
639 */ | 723 |
640 public static String getProtocolName() { | 724 |
641 return PROTOCOL; | 725 @Override |
642 } | 726 public void setUseAuthAgent(String useAuthAgent) { |
643 | 727 this.useAuthAgent = useAuthAgent; |
644 @Override | |
645 public boolean isSessionOpen() { | |
646 return sessionOpen; | |
647 } | |
648 | |
649 @Override | |
650 public boolean isConnected() { | |
651 return connected; | |
652 } | |
653 | |
654 @Override | |
655 public boolean isAuthenticated() { | |
656 return authenticated; | |
657 } | |
658 | |
659 public void connectionLost(Throwable reason) { | |
660 onDisconnect(); | |
661 } | 728 } |
662 | 729 |
663 @Override | 730 @Override |
664 public boolean canForwardPorts() { | 731 public boolean canForwardPorts() { |
665 return true; | 732 return true; |
865 Log.e(TAG, "Could not upload local file", e); | 932 Log.e(TAG, "Could not upload local file", e); |
866 return false; | 933 return false; |
867 } | 934 } |
868 } | 935 } |
869 | 936 |
870 @Override | |
871 public void setDimensions(int columns, int rows, int width, int height) { | |
872 this.columns = columns; | |
873 this.rows = rows; | |
874 | |
875 if (sessionOpen) { | |
876 try { | |
877 session.resizePTY(columns, rows, width, height); | |
878 } | |
879 catch (IOException e) { | |
880 Log.e(TAG, "Couldn't send resize PTY packet", e); | |
881 } | |
882 } | |
883 } | |
884 | 937 |
885 @Override | 938 @Override |
886 public int getDefaultPort() { | 939 public int getDefaultPort() { |
887 return DEFAULT_PORT; | 940 return DEFAULT_PORT; |
888 } | 941 } |
942 | |
943 | |
944 @Override | |
945 public boolean isConnected() { | |
946 return connected; | |
947 } | |
948 | |
949 | |
950 @Override | |
951 public boolean isSessionOpen() { | |
952 return sessionOpen; | |
953 } | |
954 | |
955 | |
956 @Override | |
957 public boolean isAuthenticated() { | |
958 return authenticated; | |
959 } | |
960 | |
889 | 961 |
890 @Override | 962 @Override |
891 public String getDefaultNickname(String username, String hostname, int port) { | 963 public String getDefaultNickname(String username, String hostname, int port) { |
892 if (port == DEFAULT_PORT) { | 964 if (port == DEFAULT_PORT) { |
893 return String.format(Locale.US, "%s@%s", username, hostname); | 965 return String.format(Locale.US, "%s@%s", username, hostname); |
895 else { | 967 else { |
896 return String.format(Locale.US, "%s@%s:%d", username, hostname, port); | 968 return String.format(Locale.US, "%s@%s:%d", username, hostname, port); |
897 } | 969 } |
898 } | 970 } |
899 | 971 |
900 public Uri getUri(String input) { | 972 |
901 Matcher matcher = hostmask.matcher(input); | 973 @Override |
902 | 974 public void getSelectionArgs(Uri uri, Map<String, String> selection) { |
903 if (!matcher.matches()) | 975 selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); |
904 return null; | 976 selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); |
905 | 977 selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); |
906 StringBuilder sb = new StringBuilder(); | 978 int port = uri.getPort(); |
907 sb.append(PROTOCOL) | 979 |
908 .append("://") | 980 if (port < 0) |
909 .append(Uri.encode(matcher.group(1))) | 981 port = DEFAULT_PORT; |
910 .append('@') | 982 |
911 .append(matcher.group(2)); | 983 selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); |
912 String portString = matcher.group(4); | 984 selection.put(HostDatabase.FIELD_HOST_USERNAME, uri.getUserInfo()); |
913 int port = DEFAULT_PORT; | 985 } |
914 | 986 |
915 if (portString != null) { | 987 |
916 try { | 988 @Override |
917 port = Integer.parseInt(portString); | 989 public HostBean createHost(Uri uri) { |
918 | 990 HostBean host = new HostBean(); |
919 if (port < 1 || port > 65535) { | 991 host.setProtocol(PROTOCOL); |
920 port = DEFAULT_PORT; | 992 host.setHostname(uri.getHost()); |
921 } | 993 int port = uri.getPort(); |
922 } | 994 |
923 catch (NumberFormatException nfe) { | 995 if (port < 0) |
924 // Keep the default port | 996 port = DEFAULT_PORT; |
925 } | 997 |
926 } | 998 host.setPort(port); |
927 | 999 host.setUsername(uri.getUserInfo()); |
928 if (port != DEFAULT_PORT) { | 1000 String nickname = uri.getFragment(); |
929 sb.append(':') | 1001 |
930 .append(port); | 1002 if (nickname == null || nickname.length() == 0) { |
931 } | 1003 host.setNickname(getDefaultNickname(host.getUsername(), |
932 | 1004 host.getHostname(), host.getPort())); |
933 sb.append("/#") | 1005 } |
934 .append(Uri.encode(input)); | 1006 else { |
935 Uri uri = Uri.parse(sb.toString()); | 1007 host.setNickname(uri.getFragment()); |
936 return uri; | 1008 } |
937 } | 1009 |
1010 return host; | |
1011 } | |
1012 | |
1013 | |
1014 public String getFormatHint(Context context) { | |
1015 return String.format("%s@%s:%s", | |
1016 context.getString(R.string.format_username), | |
1017 context.getString(R.string.format_hostname), | |
1018 context.getString(R.string.format_port)); | |
1019 } | |
1020 | |
1021 | |
1022 /** | |
1023 * @return do we use the network | |
1024 */ | |
1025 @Override | |
1026 public boolean usesNetwork() { | |
1027 return true; | |
1028 } | |
1029 | |
938 | 1030 |
939 /** | 1031 /** |
940 * Handle challenges from keyboard-interactive authentication mode. | 1032 * Handle challenges from keyboard-interactive authentication mode. |
941 */ | 1033 */ |
942 public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { | 1034 public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { |
947 // request response from user for each prompt | 1039 // request response from user for each prompt |
948 responses[i] = bridge.promptHelper.requestPasswordPrompt(instruction, prompt[i]); | 1040 responses[i] = bridge.promptHelper.requestPasswordPrompt(instruction, prompt[i]); |
949 } | 1041 } |
950 | 1042 |
951 return responses; | 1043 return responses; |
952 } | |
953 | |
954 @Override | |
955 public HostBean createHost(Uri uri) { | |
956 HostBean host = new HostBean(); | |
957 host.setProtocol(PROTOCOL); | |
958 host.setHostname(uri.getHost()); | |
959 int port = uri.getPort(); | |
960 | |
961 if (port < 0) | |
962 port = DEFAULT_PORT; | |
963 | |
964 host.setPort(port); | |
965 host.setUsername(uri.getUserInfo()); | |
966 String nickname = uri.getFragment(); | |
967 | |
968 if (nickname == null || nickname.length() == 0) { | |
969 host.setNickname(getDefaultNickname(host.getUsername(), | |
970 host.getHostname(), host.getPort())); | |
971 } | |
972 else { | |
973 host.setNickname(uri.getFragment()); | |
974 } | |
975 | |
976 return host; | |
977 } | |
978 | |
979 @Override | |
980 public void getSelectionArgs(Uri uri, Map<String, String> selection) { | |
981 selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); | |
982 selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); | |
983 selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); | |
984 int port = uri.getPort(); | |
985 | |
986 if (port < 0) | |
987 port = DEFAULT_PORT; | |
988 | |
989 selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); | |
990 selection.put(HostDatabase.FIELD_HOST_USERNAME, uri.getUserInfo()); | |
991 } | |
992 | |
993 @Override | |
994 public void setCompression(boolean compression) { | |
995 this.compression = compression; | |
996 } | |
997 | |
998 @Override | |
999 public void setHttpproxy(String httpproxy) { | |
1000 this.httpproxy = httpproxy; | |
1001 } | |
1002 | |
1003 public String getFormatHint(Context context) { | |
1004 return String.format("%s@%s:%s", | |
1005 context.getString(R.string.format_username), | |
1006 context.getString(R.string.format_hostname), | |
1007 context.getString(R.string.format_port)); | |
1008 } | |
1009 | |
1010 @Override | |
1011 public void setUseAuthAgent(String useAuthAgent) { | |
1012 this.useAuthAgent = useAuthAgent; | |
1013 } | 1044 } |
1014 | 1045 |
1015 public Map<String, byte[]> retrieveIdentities() { | 1046 public Map<String, byte[]> retrieveIdentities() { |
1016 Map<String, byte[]> pubKeys = new HashMap<String, byte[]> (manager.loadedKeypairs.size()); | 1047 Map<String, byte[]> pubKeys = new HashMap<String, byte[]> (manager.loadedKeypairs.size()); |
1017 | 1048 |
1105 | 1136 |
1106 agentLockPassphrase = lockPassphrase; | 1137 agentLockPassphrase = lockPassphrase; |
1107 return true; | 1138 return true; |
1108 } | 1139 } |
1109 | 1140 |
1110 /* (non-Javadoc) | |
1111 * @see com.five_ten_sg.connectbot.transport.AbsTransport#usesNetwork() | |
1112 */ | |
1113 @Override | |
1114 public boolean usesNetwork() { | |
1115 return true; | |
1116 } | |
1117 } | 1141 } |