source: other-projects/trunk/gs3-release-maker/tasks/sshtaskdef/src/mindbright/ssh/SSHPropertyHandler.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 36.2 KB
Line 
1/******************************************************************************
2 *
3 * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
4 * www.mindbright.se, [email protected]
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 *****************************************************************************
17 * $Author: mats $
18 * $Date: 2000/08/01 20:37:08 $
19 * $Name: rel1-2-1 $
20 *****************************************************************************/
21package mindbright.ssh;
22
23import java.io.File;
24import java.io.InputStream;
25import java.io.FileOutputStream;
26import java.io.FileInputStream;
27import java.io.ByteArrayInputStream;
28import java.io.IOException;
29import java.io.FileNotFoundException;
30import java.net.Socket;
31import java.net.InetAddress;
32import java.net.UnknownHostException;
33
34import java.util.Hashtable;
35import java.util.Properties;
36import java.util.NoSuchElementException;
37import java.util.Enumeration;
38
39import mindbright.net.*;
40import mindbright.terminal.*;
41import mindbright.security.*;
42import mindbright.util.EncryptedProperties;
43
44
45public final class SSHPropertyHandler implements SSHClientUser, SSHAuthenticator, ProxyAuthenticator {
46
47 static public final int PROP_NAME = 0;
48 static public final int PROP_VALUE = 1;
49 static public final int PROP_DESC = 2;
50 static public final int PROP_ALLOWED = 3;
51
52 static public final String PROPS_FILE_EXT = ".mtp";
53 static public final String GLOB_PROPS_FILE = "mindterm" + PROPS_FILE_EXT;
54 static public final String DEF_IDFILE = "identity";
55
56 static public final Properties defaultProperties = new Properties();
57 static public final Hashtable defaultPropertyNames = new Hashtable();
58 static public final String[][] defaultPropDesc = {
59 { "server", null, "name of server to connect to", "" },
60 { "realsrv", null, "real address of sshd if it is behind a firewall", "" },
61 { "localhst", "0.0.0.0", "address to use as localhost", "" },
62 { "port", String.valueOf(SSH.DEFAULTPORT),
63 "port on server to connect to", "" },
64 { "proxytype", "none", "type of proxy server to connect through", SSH.listSupportedProxyTypes() },
65 { "proxyhost", null, "name of proxy server to connect through", "" },
66 { "proxyport", null, "port on proxy server to connect through", "" },
67 { "proxyuser", null, "username for authentication on proxy server", "" },
68 { "proxyproto", null, "protocol for proxy connection (e.g. 'http://')", "" },
69 { "usrname", null, "username to login as", "" },
70 { "password", null, "password for normal authentication", "" },
71 { "tispassword", null, "password for TIS authentication", "" },
72 { "rsapassword", null, "password for RSA authentication (key file)", "" },
73 { "prxpassword", null, "password for proxy authentication", "" },
74 { "cipher", SSH.getCipherName(SSH.CIPHER_DEFAULT),
75 "name of block cipher to use",
76 ("( " + SSH.listSupportedCiphers() + ")") },
77 { "authtyp", "passwd", "method of authentication",
78 ("( " + SSH.listSupportedAuthTypes() + ")") },
79 { "idfile", DEF_IDFILE, "name of file containing identity (rsa key)", "" },
80 { "display", "localhost:0", "local display definition (i.e. <host>:<screen>)", "" },
81 { "mtu", "0", "maximum packet size to use (0 means use default)",
82 "(4096 - 256k)" },
83 { "escseq", "~$", "sequence of characters to type to enter local command shell", "" },
84 { "secrand", "0", "level of security in random seed (for generating session key)",
85 "(0-2, 0=low and 2=high)" },
86 { "alive", "0", "Connection keep-alive interval in seconds (0 means none)", "(0-600)" },
87 { "x11fwd", "false", "indicates whether X11 display is forwarded or not", "(true/false)" },
88 { "prvport", "false", "indicates whether to use a privileged port or not (locally)", "(true/false)" },
89 { "forcpty", "true", "indicates whether to allocate a pty or not", "(true/false)" },
90 { "remfwd", "false", "indicates whether we allow remote connects to local forwards", "(true/false)" },
91 { "idhost", "true", "indicates whether to check host's host key in 'known_hosts'", "(true/false)" },
92 { "portftp", "false", "indicates whether to enable ftp 'PORT' command support", "(true/false)" },
93 };
94
95 static {
96 for(int i = 0; i < defaultPropDesc.length; i++) {
97 String name = defaultPropDesc[i][PROP_NAME];
98 String value = defaultPropDesc[i][PROP_VALUE];
99 defaultPropertyNames.put(name, "");
100 if(value != null)
101 defaultProperties.put(name, value);
102 }
103 }
104
105 String sshHomeDir;
106 String knownHosts;
107 SSHRSAKeyFile keyFile;
108
109 SSHClient client;
110 SSHInteractor interactor;
111 EncryptedProperties props;
112 boolean activeProps;
113
114 protected String currentPropsFile;
115 protected String currentAlias;
116
117 boolean autoSaveProps;
118 boolean autoLoadProps;
119 boolean savePasswords;
120 boolean readonly;
121
122 private String propertyPassword;
123
124 public Properties initTermProps;
125
126 protected boolean propsChanged;
127
128 public SSHPropertyHandler(Properties initProps) {
129 this.knownHosts = SSH.KNOWN_HOSTS_FILE;
130
131 setProperties(initProps);
132
133 this.activeProps = false;
134 this.propsChanged = false;
135 }
136
137 public SSHPropertyHandler(SSHPropertyHandler clone) {
138 this(clone.props);
139 this.sshHomeDir = clone.sshHomeDir;
140 this.keyFile = clone.keyFile;
141 this.initTermProps = clone.initTermProps;
142 this.propertyPassword = clone.propertyPassword;
143 this.readonly = true;
144 }
145
146 public static SSHPropertyHandler fromFile(String fileName, String password) throws IOException {
147 SSHPropertyHandler fileProps = new SSHPropertyHandler(new Properties());
148 fileProps.setPropertyPassword(password);
149 fileProps.loadAbsoluteFile(fileName, false);
150 return fileProps;
151 }
152
153 public void setInteractor(SSHInteractor interactor) {
154 this.interactor = interactor;
155 }
156
157 public void setClient(SSHClient client) {
158 this.client = client;
159 }
160
161 public void setAutoLoadProps(boolean value) {
162 if(sshHomeDir != null)
163 autoLoadProps = value;
164 }
165
166 public void setAutoSaveProps(boolean value) {
167 if(sshHomeDir != null)
168 autoSaveProps = value;
169 }
170
171 public void setSavePasswords(boolean value) {
172 savePasswords = value;
173 }
174
175 public void setReadOnly(boolean value) {
176 readonly = value;
177 }
178
179 public boolean isReadOnly() {
180 return readonly;
181 }
182
183 public void setPropertyPassword(String password) {
184 if(password != null)
185 this.propertyPassword = password;
186 }
187
188 public boolean emptyPropertyPassword() {
189 return propertyPassword == null;
190 }
191
192 public void setSSHHomeDir(String sshHomeDir) {
193 if(sshHomeDir == null || sshHomeDir.trim().length() == 0) {
194 return;
195 }
196
197 if(sshHomeDir != null && !sshHomeDir.endsWith(File.separator))
198 sshHomeDir += File.separator;
199
200 if(SSH.NETSCAPE_SECURITY_MODEL) {
201 try {
202 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
203 } catch (netscape.security.ForbiddenTargetException e) {
204 // !!!
205 }
206 }
207
208 try {
209 // sshHomeDir always ends with a trailing File.separator. Strip before we
210 // try to create it (some platforms don't like ending 'separator' in name)
211 //
212 File sshDir = new File(sshHomeDir.substring(0, sshHomeDir.length() - 1));
213 if(!sshDir.exists()) {
214 if(interactor.askConfirmation("MindTerm home directory: '" + sshHomeDir +
215 "' does not exist, create it?", true)) {
216 try {
217 sshDir.mkdir();
218 } catch (Throwable t) {
219 interactor.alert("Could not create home directory, file operations disabled.");
220 sshHomeDir = null;
221 }
222 } else {
223 interactor.report("No home directory, file operations disabled.");
224 sshHomeDir = null;
225 }
226 }
227 } catch (Throwable t) {
228 if(interactor != null && interactor.isVerbose())
229 interactor.report("Can't access local file system, file operations disabled.");
230 sshHomeDir = null;
231 }
232 this.sshHomeDir = sshHomeDir;
233 if(this.sshHomeDir == null) {
234 autoSaveProps = false;
235 autoLoadProps = false;
236 }
237
238 if(interactor != null)
239 interactor.propsStateChanged(this);
240 }
241
242 public String getSSHHomeDir() {
243 return sshHomeDir;
244 }
245
246 //
247 // Methods delegated to Properties and other property related methods
248 //
249 public static boolean isProperty(String key) {
250 return defaultPropertyNames.containsKey(key) ||
251 (key.indexOf("local") == 0) || (key.indexOf("remote") == 0);
252 }
253
254 public String getProperty(String key) {
255 return props.getProperty(key);
256 }
257
258 public void setProperty(String key, String value)
259 throws IllegalArgumentException, NoSuchElementException
260 {
261 if(value == null)
262 return;
263
264 boolean equalProp = !(value.equals(getProperty(key)));
265
266 validateProperty(key, value);
267
268 if(activeProps)
269 activateProperty(key, value);
270
271 if(equalProp) {
272 if(interactor != null)
273 interactor.propsStateChanged(this);
274 propsChanged = equalProp;
275 }
276
277 props.put(key, value);
278 }
279
280 final void validateProperty(String key, String value)
281 throws IllegalArgumentException, NoSuchElementException {
282 //
283 // Some sanity checks...
284 //
285 if(key.equals("cipher")) {
286 if(SSH.getCipherType(value) == SSH.CIPHER_NOTSUPPORTED)
287 throw new IllegalArgumentException("Cipher " + value + " not supported");
288 //
289 } else if(key.equals("authtyp")) {
290 SSH.getAuthTypes(value);
291 //
292 } else if(key.equals("x11fwd") || key.equals("prvport") ||
293 key.equals("forcpty") || key.equals("remfwd") ||
294 key.equals("idhost") || key.equals("portftp")) {
295 if(!(value.equals("true") || value.equals("false")))
296 throw new IllegalArgumentException("Value for " + key + " must be 'true' or 'false'");
297 //
298 } else if(key.equals("port") || key.equals("proxyport") || key.equals("mtu") ||
299 key.equals("secrand") || key.equals("alive")) {
300 try {
301 int val = Integer.valueOf(value).intValue();
302 if((key.equals("port") || key.equals("proxyport")) && (val > 65535 || val < 0)) {
303 throw new IllegalArgumentException("Not a valid port number: " + value);
304 } else if(key.equals("mtu") && val != 0 && (val > (256*1024) || val < 4096)) {
305 throw new IllegalArgumentException("Mtu must be between 4k and 256k");
306 } else if(key.equals("alive")) {
307 if(val < 0 || val > 600)
308 throw new IllegalArgumentException("Alive interval must be 0-600");
309 } else if(key.equals("secrand")) {
310 if(val < 0 || val > 2)
311 throw new IllegalArgumentException("Secrand must be 0-2");
312 }
313 } catch (NumberFormatException e) {
314 throw new IllegalArgumentException("Value for " + key + " must be an integer");
315 }
316 //
317 } else if(key.equals("server")) {
318 if(client != null && client.isOpened()) {
319 throw new IllegalArgumentException("Server can only be set while not connected");
320 }
321 } else if(key.equals("realsrv") || key.equals("localhst")) {
322 try {
323 InetAddress.getByName(value);
324 } catch (UnknownHostException e) {
325 throw new IllegalArgumentException(key + " address must be a legal/known host name");
326 }
327 } else if(key.equals("proxytype")) {
328 SSH.getProxyType(value);
329 } else if(key.startsWith("local") || key.startsWith("remote")) {
330 try {
331 if(value.startsWith("/general/"))
332 value = value.substring(9);
333 if(key.startsWith("local"))
334 addLocalPortForward(value, false);
335 else
336 addRemotePortForward(value, false);
337 } catch (Exception e) {
338 throw new IllegalArgumentException("Not a valid port forward: " + key + " : " + value);
339 }
340 } else if(!isProperty(key)) {
341 throw new NoSuchElementException("Unknown ssh property '" + key + "'");
342 }
343 }
344
345 void activateProperty(String key, String value) {
346 //
347 // The properties that needs an action to "activated"
348 //
349 if(key.equals("remfwd")) {
350 try {
351 SSHListenChannel.setAllowRemoteConnect((new Boolean(value)).booleanValue());
352 } catch (Throwable t) {
353 // Ignore if we don't have the SSHListenChannel class
354 }
355 } else if(key.equals("portftp")) {
356 client.havePORTFtp = (new Boolean(value)).booleanValue();
357 if(client.havePORTFtp && SSHProtocolPlugin.getPlugin("ftp") != null) {
358 SSHProtocolPlugin.getPlugin("ftp").initiate(client);
359 }
360 //
361 } else if(key.equals("alive")) {
362 client.setAliveInterval(Integer.valueOf(value).intValue());
363 } else if(key.equals("secrand")) {
364 SecureRandom.secureLevel = Integer.valueOf(value).intValue();
365 //
366 } else if(key.equals("realsrv")) {
367 try {
368 if(value != null && value.length() > 0)
369 client.setServerRealAddr(InetAddress.getByName(value));
370 else
371 client.setServerRealAddr(null);
372 } catch (UnknownHostException e) {
373 // !!!
374 }
375 } else if(key.equals("localhst")) {
376 try {
377 client.setLocalAddr(value);
378 } catch (UnknownHostException e) {
379 throw new IllegalArgumentException("localhost address must be a legal/known host name");
380 }
381 } else if(key.startsWith("local")) {
382 int n = Integer.parseInt(key.substring(5));
383 if(n > client.localForwards.size())
384 throw new IllegalArgumentException("Port forwards must be given in unbroken sequence");
385 if(value.startsWith("/general/"))
386 value = value.substring(9);
387 try {
388 addLocalPortForward(value, true);
389 } catch (IOException e) {
390 throw new IllegalArgumentException("Error creating tunnel: " + e.getMessage());
391 }
392 } else if(key.startsWith("remote")) {
393 try {
394 int n = Integer.parseInt(key.substring(6));
395 if(n > client.remoteForwards.size())
396 throw new IllegalArgumentException("Port forwards must be given in unbroken sequence");
397 if(value.startsWith("/general/"))
398 value = value.substring(9);
399 addRemotePortForward(value, true);
400 } catch (Exception e) {
401 throw new IllegalArgumentException("Not a valid port forward: " + key + " : " + value);
402 }
403 }
404 }
405
406 public void setProperties(Properties newProps) throws IllegalArgumentException,
407 NoSuchElementException
408 {
409 props = new EncryptedProperties(defaultProperties);
410 mergeProperties(newProps);
411 }
412
413 public Properties getProperties() {
414 return props;
415 }
416
417 public void mergeProperties(Properties newProps) throws IllegalArgumentException,
418 NoSuchElementException
419 {
420 String name, value;
421 Enumeration enum;
422 int i;
423
424 enum = newProps.propertyNames();
425 while(enum.hasMoreElements()) {
426 name = (String)enum.nextElement();
427 value = newProps.getProperty(name);
428 if(!isProperty(name))
429 throw new NoSuchElementException("Unknown ssh property '" + name + "'");
430 props.put(name, value);
431 }
432 }
433
434 public Properties getInitTerminalProperties() {
435 return initTermProps;
436 }
437
438 public void activateProperties() {
439 if(activeProps)
440 return;
441
442 String name, value;
443 Enumeration enum = defaultPropertyNames.keys();
444
445 activeProps = true;
446
447 while(enum.hasMoreElements()) {
448 name = (String)enum.nextElement();
449 value = props.getProperty(name);
450 if(value != null)
451 activateProperty(name, value);
452 }
453 int i = 0;
454 while((value = props.getProperty("local" + i)) != null) {
455 activateProperty("local" + i, value);
456 i++;
457 }
458 i = 0;
459 while((value = props.getProperty("remote" + i)) != null) {
460 activateProperty("remote" + i, value);
461 i++;
462 }
463 }
464
465 public void passivateProperties() {
466 activeProps = false;
467 }
468
469 private void saveProperties(String fname) throws IOException {
470 FileOutputStream f;
471 Terminal term = getTerminal();
472 Properties termProps = (term != null ? term.getProperties() : null);
473
474 if(SSH.NETSCAPE_SECURITY_MODEL) {
475 try {
476 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
477 } catch (netscape.security.ForbiddenTargetException e) {
478 // !!!
479 }
480 }
481
482 if(termProps != null) {
483 Enumeration e = termProps.keys();
484 while(e.hasMoreElements()) {
485 String key = (String)e.nextElement();
486 String val = termProps.getProperty(key);
487 props.put(key, val);
488 }
489 }
490
491 f = new FileOutputStream(fname);
492
493 if(savePasswords) {
494 // !!! REMOVE
495 if(propertyPassword == null) {
496 propertyPassword = "";
497 }
498 // TODO: should take default cipher from defaultProperties
499 props.save(f, "MindTerm ssh settings",
500 propertyPassword, SSH.cipherClasses[SSH.CIPHER_DEFAULT][0]);
501 } else {
502 String prxPwd, stdPwd, tisPwd, rsaPwd;
503 stdPwd = props.getProperty("password");
504 prxPwd = props.getProperty("prxpassword");
505 tisPwd = props.getProperty("tispassword");
506 rsaPwd = props.getProperty("rsapassword");
507 clearPasswords();
508 props.save(f, "MindTerm ssh settings");
509 if(stdPwd != null) props.put("password", stdPwd);
510 if(prxPwd != null) props.put("prxpassword", prxPwd);
511 if(tisPwd != null) props.put("tispassword", tisPwd);
512 if(rsaPwd != null) props.put("rsapassword", rsaPwd);
513 }
514
515 f.close();
516
517 propsChanged = false;
518 if(term != null)
519 term.setPropsChanged(false);
520
521 interactor.propsStateChanged(this);
522 }
523
524 private void loadProperties(String fname, boolean promptPwd) throws IOException {
525 Terminal term = getTerminal();
526
527 if(SSH.NETSCAPE_SECURITY_MODEL) {
528 try {
529 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
530 } catch (netscape.security.ForbiddenTargetException e) {
531 // !!!
532 }
533 }
534
535 FileInputStream f = new FileInputStream(fname);
536 byte[] bytes = new byte[f.available()];
537 f.read(bytes);
538 ByteArrayInputStream bytein = new ByteArrayInputStream(bytes);
539 f.close();
540
541 EncryptedProperties loadProps = new EncryptedProperties();
542
543 try {
544 loadProps.load(bytein, "");
545 } catch (AccessDeniedException e) {
546 try {
547 bytein.reset();
548 loadProps.load(bytein, propertyPassword);
549 } catch (AccessDeniedException ee) {
550 try {
551 if(promptPwd) {
552 bytein.reset();
553 propertyPassword = interactor.promptPassword("File " + fname + " password: ");
554 loadProps.load(bytein, propertyPassword);
555 } else {
556 throw new AccessDeniedException("");
557 }
558 } catch (AccessDeniedException eee) {
559 clearServerSetting();
560 throw new SSHClient.AuthFailException("Access denied for '" + fname + "'");
561 }
562 }
563 }
564
565 savePasswords = !loadProps.isNormalPropsFile();
566
567 Enumeration enum;
568 String name;
569
570 Properties sshProps = new Properties();
571 Properties termProps = new Properties();
572
573 enum = loadProps.keys();
574 while(enum.hasMoreElements()) {
575 name = (String)enum.nextElement();
576 if(isProperty(name))
577 sshProps.put(name, loadProps.getProperty(name));
578 else if(TerminalDefProps.isProperty(name))
579 termProps.put(name, loadProps.getProperty(name));
580 else {
581 if(interactor != null)
582 interactor.report("Unknown property '" + name + "' found in file: " + fname);
583 else
584 System.out.println("Unknown property '" + name + "' found in file: " + fname);
585 }
586 }
587
588 if(client != null)
589 client.clearAllForwards();
590
591 passivateProperties();
592
593 setProperties(sshProps);
594
595 initTermProps = termProps;
596
597 if(term != null) {
598 term.setProperties(initTermProps, false);
599 term.setPropsChanged(false);
600 }
601
602 propsChanged = false;
603 if(interactor != null)
604 interactor.propsStateChanged(this);
605 }
606
607 final void clearPasswords() {
608 props.remove("password");
609 props.remove("tispassword");
610 props.remove("rsapassword");
611 props.remove("prxpassword");
612 }
613
614 final void clearServerSetting() {
615 setProperty("server", "");
616 currentPropsFile = null;
617 currentAlias = null;
618 if(interactor != null)
619 interactor.propsStateChanged(this);
620 }
621
622 final void clearAllForwards() {
623 int i = 0;
624 if(client != null)
625 client.clearAllForwards();
626 for(i = 0; i < 1024; i++) {
627 String key = "local" + i;
628 if(!props.containsKey(key))
629 break;
630 props.remove(key);
631 }
632 for(i = 0; i < 1024; i++) {
633 String key = "remote" + i;
634 if(!props.containsKey(key))
635 break;
636 props.remove(key);
637 }
638 }
639
640 public boolean wantSave() {
641 boolean somePropsChanged = (propsChanged ||
642 (getTerminal() != null ?
643 getTerminal().getPropsChanged() : false));
644 return (!isReadOnly() && somePropsChanged && sshHomeDir != null &&
645 currentAlias != null);
646 }
647
648 public final void checkSave() throws IOException {
649 if(autoSaveProps) {
650 saveCurrentFile();
651 }
652 }
653
654 public void saveCurrentFile() throws IOException {
655 if(currentPropsFile != null && wantSave())
656 saveProperties(currentPropsFile);
657 }
658
659 public void saveAsCurrentFile(String fileName) throws IOException {
660 propsChanged = true;
661 currentPropsFile = fileName;
662 saveCurrentFile();
663 currentAlias = null;
664 }
665
666 public void loadAbsoluteFile(String fileName, boolean promptPwd) throws IOException {
667 currentAlias = null;
668 currentPropsFile = fileName;
669
670 loadProperties(currentPropsFile, promptPwd);
671 if(interactor != null)
672 interactor.propsStateChanged(this);
673 }
674
675 public void setAlias(String alias) {
676 if(sshHomeDir == null)
677 return;
678 currentAlias = alias;
679 currentPropsFile = sshHomeDir + alias + PROPS_FILE_EXT;
680 }
681
682 public String getAlias() {
683 return currentAlias;
684 }
685
686 public void loadAliasFile(String alias, boolean promptPwd) throws IOException {
687 String oldAlias = currentAlias;
688 setAlias(alias);
689 if(oldAlias == null || !oldAlias.equals(alias)) {
690 loadProperties(currentPropsFile, promptPwd);
691 }
692 }
693
694 public String[] availableAliases() {
695 if(sshHomeDir == null)
696 return null;
697
698 if(SSH.NETSCAPE_SECURITY_MODEL) {
699 try {
700 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
701 } catch (netscape.security.ForbiddenTargetException e) {
702 // !!!
703 }
704 }
705
706 // sshHomeDir always ends with a trailing File.separator. Strip before we
707 // try to create it (some platforms don't like ending 'separator' in name)
708 //
709 File dir = new File(sshHomeDir.substring(0, sshHomeDir.length() - 1));
710 String[] list, alist;
711 int i, cnt = 0;
712
713 list = dir.list();
714 for(i = 0; i < list.length; i++) {
715 if(!list[i].endsWith(PROPS_FILE_EXT)) {
716 list[i] = null;
717 cnt++;
718 }
719 }
720 if(cnt == list.length)
721 return null;
722 alist = new String[list.length - cnt];
723 cnt = 0;
724 for(i = 0; i < list.length; i++) {
725 if(list[i] != null) {
726 int pi = list[i].lastIndexOf(PROPS_FILE_EXT);
727 alist[cnt++] = list[i].substring(0, pi);
728 }
729 }
730
731 return alist;
732 }
733
734 public boolean isAlias(String alias) {
735 String[] aliases = availableAliases();
736 boolean isAlias = false;
737 if(aliases != null) {
738 for(int i = 0; i < aliases.length; i++)
739 if(alias.equals(aliases[i])) {
740 isAlias = true;
741 break;
742 }
743 }
744 return isAlias;
745 }
746
747 public boolean isAbsolutFile(String fileName) {
748 if(sshHomeDir == null)
749 return false;
750
751 if(SSH.NETSCAPE_SECURITY_MODEL) {
752 try {
753 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
754 } catch (netscape.security.ForbiddenTargetException e) {
755 // !!!
756 }
757 }
758
759 File file = new File(fileName);
760 return (file.isFile() && file.exists());
761 }
762
763 public Terminal getTerminal() {
764 if(client == null || client.console == null)
765 return null;
766 Terminal term = client.console.getTerminal();
767 return term;
768 }
769
770 public void removeLocalTunnelAt(int idx, boolean kill) {
771 int i, sz = client.localForwards.size();
772 props.remove("local" + idx);
773 for(i = idx; i < sz - 1; i++) {
774 props.put("local" + idx, props.get("local" + (idx + 1)));
775 props.remove("local" + idx + 1);
776 }
777 propsChanged = true;
778 if(kill) {
779 SSHClient.LocalForward fwd = (SSHClient.LocalForward)client.localForwards.elementAt(idx);
780 client.delLocalPortForward(fwd.localHost, fwd.localPort);
781 } else {
782 client.localForwards.removeElementAt(idx);
783 }
784 }
785
786 public void removeRemoteTunnelAt(int idx) {
787 int i, sz = client.remoteForwards.size();
788 props.remove("remote" + idx);
789 for(i = idx; i < sz - 1; i++) {
790 props.put("remote" + idx, props.get("remote" + (idx + 1)));
791 props.remove("remote" + idx + 1);
792 }
793 propsChanged = true;
794 client.remoteForwards.removeElementAt(idx);
795 }
796
797 public void addLocalPortForward(String fwdSpec, boolean commit) throws IllegalArgumentException,
798 IOException {
799 int localPort;
800 String remoteHost;
801 int remotePort;
802 int d1, d2, d3;
803 String tmp, plugin;
804 String localHost = null;
805
806 if(fwdSpec.charAt(0) == '/') {
807 int i = fwdSpec.lastIndexOf('/');
808 if(i == 0)
809 throw new IllegalArgumentException("Invalid port forward spec. " + fwdSpec);
810 plugin = fwdSpec.substring(1, i);
811 fwdSpec = fwdSpec.substring(i + 1);
812 } else
813 plugin = "general";
814
815 d1 = fwdSpec.indexOf(':');
816 d2 = fwdSpec.lastIndexOf(':');
817 if(d1 == d2)
818 throw new IllegalArgumentException("Invalid port forward spec. " + fwdSpec);
819
820 d3 = fwdSpec.indexOf(':', d1 + 1);
821
822 if(d3 != d2) {
823 localHost = fwdSpec.substring(0, d1);
824 localPort = Integer.parseInt(fwdSpec.substring(d1 + 1, d3));
825 remoteHost = fwdSpec.substring(d3 + 1, d2);
826 } else {
827 localPort = Integer.parseInt(fwdSpec.substring(0, d1));
828 remoteHost = fwdSpec.substring(d1 + 1, d2);
829 }
830
831 tmp = fwdSpec.substring(d2 + 1);
832 remotePort = Integer.parseInt(tmp);
833 if(commit) {
834 if(localHost == null)
835 client.addLocalPortForward(localPort, remoteHost, remotePort, plugin);
836 else
837 client.addLocalPortForward(localHost, localPort, remoteHost, remotePort, plugin);
838 }
839 }
840
841 public void addRemotePortForward(String fwdSpec, boolean commit) throws IllegalArgumentException {
842 int remotePort;
843 int localPort;
844 String localHost;
845 int d1, d2;
846 String tmp, plugin;
847
848 if(fwdSpec.charAt(0) == '/') {
849 int i = fwdSpec.lastIndexOf('/');
850 if(i == 0)
851 throw new IllegalArgumentException("Invalid port forward spec.");
852 plugin = fwdSpec.substring(1, i);
853 fwdSpec = fwdSpec.substring(i + 1);
854 } else
855 plugin = "general";
856
857 d1 = fwdSpec.indexOf(':');
858 d2 = fwdSpec.lastIndexOf(':');
859 if(d1 == d2)
860 throw new IllegalArgumentException("Invalid port forward spec.");
861
862 tmp = fwdSpec.substring(0, d1);
863 remotePort = Integer.parseInt(tmp);
864 localHost = fwdSpec.substring(d1 + 1, d2);
865 tmp = fwdSpec.substring(d2 + 1);
866 localPort = Integer.parseInt(tmp);
867 if(commit) {
868 client.addRemotePortForward(remotePort, localHost, localPort, plugin);
869 }
870 }
871
872 //
873 // SSHAuthenticator interface
874 //
875 public String getUsername(SSHClientUser origin) throws IOException {
876 String username = getProperty("usrname");
877 if(!interactor.quietPrompts() || (username == null || username.equals(""))) {
878 String username2 = interactor.promptLine(getProperty("server") + " login: ", username);
879 if(!username2.equals(username)) {
880 clearPasswords();
881 username = username2;
882 }
883 setProperty("usrname", username); // Changing the user name does not save new properties...
884 }
885 return username;
886 }
887
888 public String getPassword(SSHClientUser origin) throws IOException {
889 String password = getProperty("password");
890 if(password == null) {
891 password = interactor.promptPassword(getProperty("usrname") + "@" +
892 getProperty("server") + "'s password: ");
893 setProperty("password", password);
894 }
895 return password;
896 }
897
898 public String getChallengeResponse(SSHClientUser origin, String challenge) throws IOException {
899 String tisPassword = getProperty("tispassword");
900 if(tisPassword == null) {
901 tisPassword = interactor.promptPassword(challenge);
902 setProperty("tispassword", tisPassword);
903 }
904 return tisPassword;
905 }
906
907 public int[] getAuthTypes(SSHClientUser origin) {
908 return SSH.getAuthTypes(getProperty("authtyp"));
909 }
910
911 public int getCipher(SSHClientUser origin) {
912 return SSH.getCipherType(getProperty("cipher"));
913 }
914
915 public SSHRSAKeyFile getIdentityFile(SSHClientUser origin) throws IOException {
916 String idFile = getProperty("idfile");
917 if(idFile.indexOf(File.separator) == -1) {
918 idFile = sshHomeDir + idFile;
919 }
920
921 if(SSH.NETSCAPE_SECURITY_MODEL) {
922 try {
923 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
924 } catch (netscape.security.ForbiddenTargetException e) {
925 // !!!
926 }
927 }
928
929 keyFile = new SSHRSAKeyFile(idFile);
930 return keyFile;
931 }
932
933 public String getIdentityPassword(SSHClientUser origin) throws IOException {
934 String rsaPassword = getProperty("rsapassword");
935 if(rsaPassword == null) {
936 rsaPassword = interactor.promptPassword("key file '" + keyFile.getComment() +
937 "' password: ");
938 setProperty("rsapassword", rsaPassword);
939 }
940 return rsaPassword;
941 }
942
943 public boolean verifyKnownHosts(RSAPublicKey hostPub) throws IOException {
944 if(!Boolean.valueOf(getProperty("idhost")).booleanValue()) {
945 return true;
946 }
947
948 File tmpFile;
949 String fileName = null;
950 InputStream knownHostsIn = null;
951 int hostCheck = 0;
952 boolean confirm = true;
953
954 SSHRSAPublicKeyFile file = null;
955
956 knownHostsIn = this.getClass().getResourceAsStream("/defaults/known_hosts.txt");
957
958 try {
959 boolean tryingResource = true;
960 while(tryingResource) {
961 if(knownHostsIn != null) {
962 fileName = "<resource>/defaults/known_hosts.txt";
963 if(interactor.isVerbose())
964 interactor.report("Found preinstalled 'known_hosts' file.");
965 } else {
966 tryingResource = false;
967 if(sshHomeDir == null) {
968 if(interactor.isVerbose())
969 interactor.report("File operations disabled, server identity can't be verified");
970 return true;
971 }
972
973 if(SSH.NETSCAPE_SECURITY_MODEL) {
974 try {
975 netscape.security.PrivilegeManager.enablePrivilege("UniversalFileAccess");
976 } catch (netscape.security.ForbiddenTargetException e) {
977 // !!!
978 }
979 }
980
981 fileName = sshHomeDir + knownHosts;
982 tmpFile = new File(fileName);
983
984 if(!tmpFile.exists()) {
985 if(interactor.askConfirmation("File '" + fileName + "' not found, create it?", true)) {
986 FileOutputStream f = new FileOutputStream(tmpFile);
987 f.close();
988 } else {
989 interactor.report("Verification of server key disabled in this session.");
990 return true;
991 }
992 }
993
994 knownHostsIn = new FileInputStream(fileName);
995 }
996
997 file = new SSHRSAPublicKeyFile(knownHostsIn, fileName, true);
998
999 if((hostCheck = file.checkPublic(hostPub.getN(), getProperty("server"))) ==
1000 SSH.SRV_HOSTKEY_KNOWN)
1001 return true;
1002
1003 if(tryingResource) {
1004 if(!interactor.askConfirmation("Host was not found in preinstalled 'known_hosts' file! Continue anyway?", false))
1005 return false;
1006 }
1007
1008 knownHostsIn = null;
1009 }
1010
1011 if(hostCheck == SSH.SRV_HOSTKEY_NEW) {
1012 if(interactor.isVerbose())
1013 interactor.report("Host key not found from the list of known hosts.");
1014 if(!interactor.askConfirmation("Do you want to add this host to your set of known hosts", true)) {
1015 interactor.report("Verification of server key disabled in this session.");
1016 return true;
1017 }
1018 confirm = true;
1019 } else {
1020 interactor.alert("WARNING: HOST IDENTIFICATION HAS CHANGED! " +
1021 "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY, " +
1022 "ONLY PROCEED IF YOU KNOW WHAT YOU ARE DOING!");
1023 confirm = interactor.askConfirmation("Do you want to replace the identification of this host?",
1024 false);
1025 file.removePublic(getProperty("server"));
1026 }
1027
1028 if(confirm) {
1029 file.addPublic(getProperty("server"), null, hostPub.getE(), hostPub.getN());
1030 tmpFile = new File(fileName + ".tmp");
1031 File oldFile = new File(fileName);
1032 oldFile.renameTo(tmpFile);
1033 try {
1034 file.saveToFile(fileName);
1035 } catch (IOException e) {
1036 oldFile = new File(fileName);
1037 tmpFile.renameTo(oldFile);
1038 throw e;
1039 }
1040 tmpFile.delete();
1041 } else {
1042 return false;
1043 }
1044 } finally {
1045 try { knownHostsIn.close(); } catch (Exception e) {}
1046 }
1047
1048 return true;
1049 }
1050
1051 //
1052 // ProxyAuthenticator interface
1053 //
1054
1055 public String getProxyUsername(String type, String challenge) throws IOException {
1056 String username = getProperty("proxyuser");
1057 if(!interactor.quietPrompts() || (username == null || username.equals(""))) {
1058 String chStr = (challenge != null ? (" '" + challenge + "'") : "");
1059 username = interactor.promptLine(type + chStr + " username: ", username);
1060 setProperty("proxyuser", username);
1061 }
1062 return username;
1063 }
1064
1065 public String getProxyPassword(String type, String challenge) throws IOException {
1066 String prxPassword = getProperty("prxpassword");
1067 if(prxPassword == null) {
1068 String chStr = (challenge != null ? (" '" + challenge + "'") : "");
1069 prxPassword = interactor.promptPassword(type + chStr + " password: ");
1070 setProperty("prxpassword", prxPassword);
1071 }
1072 return prxPassword;
1073 }
1074
1075 //
1076 // SSHClientUser interface
1077 //
1078
1079 public String getSrvHost() throws IOException {
1080 String host = getProperty("server");
1081
1082 if(!interactor.quietPrompts() || (host == null || host.equals(""))) {
1083 if(currentAlias != null)
1084 host = currentAlias;
1085 do {
1086 host = interactor.promptLine("SSH Server/Alias: ", host);
1087 host = host.trim();
1088 } while ("".equals(host));
1089
1090 if(autoLoadProps) {
1091 if(isAlias(host)) {
1092 loadAliasFile(host, true);
1093 } else if(isAbsolutFile(host)) {
1094 loadAbsoluteFile(host, true);
1095 } else if(sshHomeDir != null) {
1096 String pwdChk = "";
1097 String alias;
1098 do {
1099 alias = interactor.promptLine("No settings file for " + host +
1100 " found.\n\rSave as alias: ", host);
1101 alias = alias.trim();
1102 if(savePasswords) {
1103 pwdChk = interactor.promptPassword(alias + " file password: ");
1104 if(pwdChk.length() > 0)
1105 propertyPassword = interactor.promptPassword(alias + " password again: ");
1106 }
1107 } while ("".equals(alias) ||
1108 (!pwdChk.equals("") && !pwdChk.equals(propertyPassword)));
1109 setAlias(alias);
1110 setProperty("server", host);
1111
1112 // Might be same host/user/pwd but we don't know, it's a
1113 // different alias so we better clear stuff here so the user
1114 // can change "identity" in another alias (otherwise if
1115 // quietPrompts are used the user might not get a chance to
1116 // do this). Also, tunnels are no longer "auto-transfered"
1117 // between aliases.
1118 //
1119 clearPasswords();
1120 clearAllForwards();
1121 props.remove("usrname");
1122 propsChanged = true;
1123 }
1124 host = getProperty("server");
1125 } else {
1126 setProperty("server", host);
1127 }
1128 }
1129
1130 activateProperties();
1131
1132 return host;
1133 }
1134
1135 public int getSrvPort() {
1136 return Integer.valueOf(getProperty("port")).intValue();
1137 }
1138
1139 public Socket getProxyConnection() throws IOException {
1140 String proxyType = getProperty("proxytype");
1141 int proxyTypeId = SSH.PROXY_NONE;
1142
1143 try {
1144 proxyTypeId = SSH.getProxyType(proxyType);
1145 } catch (IllegalArgumentException e) {
1146 throw new IOException(e.getMessage());
1147 }
1148
1149 if(proxyTypeId == SSH.PROXY_NONE) {
1150 return null;
1151 }
1152
1153 String prxHost = getProperty("proxyhost");
1154 int prxPort = -1;
1155
1156 try {
1157 prxPort = Integer.valueOf(getProperty("proxyport")).intValue();
1158 } catch (Exception e) {
1159 prxPort = -1;
1160 }
1161
1162 if(prxHost == null || prxPort == -1) {
1163 throw new IOException("When 'proxytype' is set, 'proxyhost' and 'proxyport' must also be set");
1164 }
1165
1166 String sshHost = getProperty("server");
1167 int sshPort = getSrvPort();
1168 String prxProt = getProperty("proxyproto");
1169
1170 Socket proxySocket = null;
1171
1172 switch(proxyTypeId) {
1173 case SSH.PROXY_HTTP:
1174 proxySocket = WebProxyTunnelSocket.getProxy(sshHost, sshPort, prxHost, prxPort, prxProt,
1175 this, "MindTerm/" + SSH.CVS_NAME);
1176 break;
1177 case SSH.PROXY_SOCKS4:
1178 proxySocket = SocksProxySocket.getSocks4Proxy(sshHost, sshPort, prxHost, prxPort,
1179 getProxyUsername("SOCKS4", null));
1180 break;
1181 case SSH.PROXY_SOCKS5_DNS:
1182 proxySocket = SocksProxySocket.getSocks5Proxy(sshHost, sshPort,
1183 prxHost, prxPort,
1184 false, this);
1185 break;
1186 case SSH.PROXY_SOCKS5_IP:
1187 proxySocket = SocksProxySocket.getSocks5Proxy(sshHost, sshPort,
1188 prxHost, prxPort,
1189 true, this);
1190 break;
1191 }
1192
1193 return proxySocket;
1194 }
1195
1196 public String getDisplay() {
1197 return getProperty("display");
1198 }
1199
1200 public int getMaxPacketSz() {
1201 return Integer.valueOf(getProperty("mtu")).intValue();
1202 }
1203
1204 public int getAliveInterval() {
1205 return Integer.valueOf(getProperty("alive")).intValue();
1206 }
1207
1208 public boolean wantX11Forward() {
1209 return Boolean.valueOf(getProperty("x11fwd")).booleanValue();
1210 }
1211
1212 public boolean wantPrivileged() {
1213 return Boolean.valueOf(getProperty("prvport")).booleanValue();
1214 }
1215
1216 public boolean wantPTY() {
1217 return Boolean.valueOf(getProperty("forcpty")).booleanValue();
1218 }
1219
1220 public SSHInteractor getInteractor() {
1221 return interactor;
1222 }
1223
1224}
Note: See TracBrowser for help on using the repository browser.