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 }