Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: mindbright/ssh/SSHTunnelingClient.java


1   /******************************************************************************
2    *
3    * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
4    *                 www.mindbright.se, info@mindbright.se
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: nallen $
18   * $Date: 2001/11/12 16:31:23 $
19   * $Name:  $
20   *****************************************************************************/
21  package mindbright.ssh;
22  
23  import java.io.IOException;
24  import java.io.FileNotFoundException;
25  import java.net.UnknownHostException;
26  
27  import java.awt.*;
28  import java.awt.event.*;
29  
30  import java.io.InputStream;
31  import java.io.ByteArrayOutputStream;
32  
33  import mindbright.application.MindTunnelCli;
34  
35  import mindbright.util.AWTConvenience;
36  
37  public class SSHTunnelingClient extends SSHClient implements Runnable, SSHInteractor {
38  
39      public static class Logo extends Component {
40    Image logo;
41  
42    public Logo(Image logo) {
43        this.logo = logo;
44    }
45  
46    public Dimension getMinimumSize() {
47        return getPreferredSize();
48    }
49  
50    public Dimension getPreferredSize() {
51        int width  = -1;
52        int height = -1;
53        boolean ready = false;
54  
55        while (!ready) {
56      width  = logo.getWidth(null);
57      height = logo.getHeight(null);
58      if(width != -1 && height != -1) {
59          ready = true;
60      }
61      Thread.yield();
62        }
63        Dimension dim = new Dimension(width, height);
64  
65        return dim;
66    }
67  
68    public void paint(Graphics g) {
69        if(logo == null)
70      return;
71        Dimension d = getSize();
72        g.drawImage(logo, 0, 0, d.width, d.height, this);
73    }
74      }
75  
76      public static final boolean expires  = false;
77      public static final boolean licensed = false;
78  
79      public static final long validFrom = 965157940452L; // 000801/21:25
80      public static final long validTime = (33L * 24L * 60L * 60L * 1000L);
81  
82      public boolean verbose          = false;
83      public boolean listMode         = false;
84      public boolean haveTunnelDialog = false;
85      public boolean haveSCPDialog    = false;
86      public boolean haveProxyDialog  = false;
87      public boolean haveServer       = false;
88  
89      Thread clientThread = null;
90  
91      MindTunnelCli tunnelClient;
92  
93      Frame parent;
94  
95      int logoPlacement;
96  
97      SSHPropertyHandler propsHandler;
98  
99      public SSHTunnelingClient(SSHPropertyHandler propsHandler, MindTunnelCli tunnelClient) {
100   super(propsHandler, propsHandler);
101 
102   this.propsHandler = propsHandler;
103   this.interactor   = this; // !!! OUCH
104 
105   this.tunnelClient = tunnelClient;
106 
107   propsHandler.setInteractor(this);
108   propsHandler.setClient(this);
109     }
110 
111     boolean hasExpired() {
112   boolean expired = false;
113   long now = System.currentTimeMillis();
114 
115   if(licensed)
116       return false;
117 
118   if(expires) {
119       int daysRemaining = (int)((validTime - (now - validFrom)) / (1000L * 60L * 60L * 24L));
120       if(daysRemaining <= 0) {
121     alertDialog("This is a demo version of MindTunnel, it has expired!");
122     expired = true;
123       } else {
124     alertDialog("This is a demo version of MindTunnel, it will expire in " + daysRemaining + " days");
125       }
126   } else {
127       int daysOld = (int)((now - validFrom) / (1000L * 60L * 60L * 24L));
128       alertDialog("This is a demo version of MindTunnel, it is " + daysOld + " days old.");
129   }
130   return expired;
131     }
132 
133     public SSHPropertyHandler getPropertyHandler() {
134   return propsHandler;
135     }
136 
137     public void run() {
138   clientThread = Thread.currentThread();
139 
140   String srv = propsHandler.getProperty("server");
141   if(srv != null && srv.trim().length() != 0) {
142       haveServer = true;
143   }
144 
145   showMainWindow();
146 
147   if(hasExpired()) {
148       parent.dispose();
149       return;
150   }
151 
152     /*if(NETSCAPE_SECURITY_MODEL) {
153       try {
154     netscape.security.PrivilegeManager.enablePrivilege("TerminalEmulator");
155       } catch (netscape.security.ForbiddenTargetException e) {
156     alertDialog("Full network access denied, normal applet security applies");
157       }
158      }*/
159 
160   while(true) {
161       parent.setTitle(SSH.VER_MINDTUNL + " (offline)");
162       updateButtons();
163 
164       if(listMode) {
165     choiceHosts.requestFocus();
166       } else if(haveServer) {
167     textUser.requestFocus();
168       } else {
169     textSrv.requestFocus();
170       }
171 
172       try {
173     // This starts a connection to the sshd and all the related stuff...
174     //
175     bootSSH(true);
176 
177     parent.setTitle(propsHandler.getProperty("usrname") +
178         "@" + propsHandler.getProperty("server") +
179         " (online)");
180 
181     // Tell MindTunnelCli that we are now online
182     //
183     tunnelClient.online();
184 
185     // Join main receiver channel thread and wait for session to end
186     //
187     controller.waitForExit();
188 
189       } catch(SSHClient.AuthFailException e) {
190     alertDialog(e.getMessage());
191     propsHandler.clearPasswords();
192 
193       } catch(UnknownHostException e) {
194     String host = e.getMessage();
195     String msg;
196     if(propsHandler.getProperty("proxytype").equals("none")) {
197         msg = "Unknown host: " + host;
198     } else {
199         msg = "Unknown proxy host: " + host;
200     }
201     alertDialog(msg);
202     propsHandler.clearServerSetting();
203 
204       } catch(FileNotFoundException e) {
205     alertDialog("File not found: " + e.getMessage());
206 
207       } catch(Exception e) {
208     String msg = e.getMessage();
209     if(msg == null || msg.trim().length() == 0)
210         msg = e.toString();
211     msg = "Error connecting to " + propsHandler.getProperty("server") + ", reason: " + msg;
212     if(SSH.DEBUGMORE) {
213         System.out.println("If an error occured, please send the below stacktrace to mats@mindbright.se");
214         e.printStackTrace();
215     }
216     alertDialog(msg);
217 
218       } catch(ThreadDeath death) {
219     if(controller != null)
220         controller.killAll();
221     controller = null;
222     throw death;
223       }
224 
225       propsHandler.passivateProperties();
226       if(usedOTP) {
227     propsHandler.clearPasswords();
228       }
229   }
230     }
231 
232     public void updateButtons() {
233   boolean isConn = isConnected();
234   connBut.setEnabled(!isConn);
235   discBut.setEnabled(isConn);
236   if(listMode) {
237       choiceHosts.setEnabled(!isConn);
238   } else {
239       if(!haveServer)
240     textSrv.setEnabled(!isConn);
241       textUser.setEnabled(!isConn);
242       textPasswd.setEnabled(!isConn);
243   }
244 
245   if(tunnelBut != null)
246       tunnelBut.setEnabled(isConn);
247   if(scpBut != null)
248       scpBut.setEnabled(isConn);
249   if(proxyBut != null)
250       proxyBut.setEnabled(!isConn);
251     }
252 
253     //
254     // SSHInteractor interface
255     //
256     public void propsStateChanged(SSHPropertyHandler props) {
257     }
258 
259     public void startNewSession(SSHClient client) {
260   try {
261       synchronized(this) {
262     this.wait();
263       }
264   } catch (InterruptedException e) {
265   }
266   if(listMode) {
267       try {
268     String host = choiceHosts.getSelectedItem();
269     String pwd = "";
270     do {
271         try {
272       propsHandler.setPropertyPassword(pwd);
273       propsHandler.loadAliasFile(host, false);
274       break;
275         } catch(SSHClient.AuthFailException ee) {
276         }
277     } while((pwd = passwordDialog("Please give file password for " +
278                 host, "MindTunnel - File Password")) != null);
279         } catch (Throwable t) {
280       alertDialog("Error loading settings: " + t.getMessage());
281         }
282   } else {
283       if(!haveServer)
284     propsHandler.setProperty("server", textSrv.getText());
285       propsHandler.setProperty("usrname", textUser.getText());
286       String password = textPasswd.getText();
287       propsHandler.setProperty("password", password);
288       propsHandler.setProperty("rsapassword", password);
289       propsHandler.setProperty("tispassword", password);
290       propsHandler.setPropertyPassword(password);
291       textPasswd.setText("");
292   }
293 
294   propsHandler.setProperty("forcpty", "false");
295     }
296 
297     public void sessionStarted(SSHClient client) {
298     }
299 
300     public boolean quietPrompts() {
301   return true;
302     }
303 
304     public String promptLine(String prompt, String defaultVal) throws IOException {
305   return null;
306     }
307 
308     public String promptPassword(String prompt) throws IOException {
309   String pwd = passwordDialog(prompt, "MindTunnel - Password");
310   if(pwd == null) {
311       throw new IOException("Login canceled by user");
312   }
313   return pwd;
314     }
315 
316     public boolean isVerbose() {
317   return verbose;
318     }
319 
320     public boolean askConfirmation(String message, boolean defAnswer) {
321   return confirmDialog(message, defAnswer);
322     }
323 
324     public void connected(SSHClient client) {
325     }
326 
327     public void open(SSHClient client) {
328   updateButtons();
329     }
330 
331     public void disconnected(SSHClient client, boolean graceful) {
332   updateButtons();
333     }
334 
335     public void report(String msg) {
336   if(verbose) {
337       System.out.println(msg);
338       System.out.println("");
339   }
340     }
341 
342     public void alert(String msg) {
343   alertDialog(msg);
344     }
345 
346     public void windowClosing(WindowEvent e) {
347   if(!isConnected()) {
348       parent.dispose();
349       clientThread.stop();
350   } else {
351       alertDialog("Please disconnect before exiting!");
352   }
353     }
354 
355     Choice choiceHosts;
356     TextField textSrv, textUser, textPasswd;
357     Button connBut, discBut, tunnelBut, scpBut, proxyBut;
358     public final void showMainWindow() {
359   parent = new Frame();
360   parent.addWindowListener(new WindowAdapter() {
361       public void windowClosing(WindowEvent e)  { SSHTunnelingClient.this.windowClosing(e); }
362   });
363 
364   if(listMode && propsHandler.availableAliases() == null) {
365       listMode = false;
366       alertDialog("Must have home directory with aliases to use list mode");
367   }
368 
369   GridBagLayout       grid  = new GridBagLayout();
370   GridBagConstraints  gridc = new GridBagConstraints();
371 
372   ActionListener      al;
373   Label               lbl;
374   Panel               p = new Panel();
375 
376   p.setLayout(grid);
377 
378   gridc.insets    = new Insets(4, 4, 4, 4);
379   gridc.fill      = GridBagConstraints.HORIZONTAL;
380   gridc.weightx   = 1.0;
381   gridc.gridy     = 0;
382   gridc.gridwidth = 1;
383   gridc.anchor    = GridBagConstraints.WEST;
384 
385   String[] l = propsHandler.availableAliases();
386   if(listMode && l != null) {
387       lbl = new Label("SSH Server:");
388       grid.setConstraints(lbl, gridc);
389       p.add(lbl);
390 
391       choiceHosts = new Choice();
392       for(int i = 0; i < l.length; i++) {
393     choiceHosts.add(l[i]);
394       }
395       choiceHosts.select(0);
396       grid.setConstraints(choiceHosts, gridc);
397       p.add(choiceHosts);
398       gridc.gridy += 1;
399   } else {
400 
401       if(!haveServer) {
402     gridc.weightx   = 0;
403     lbl = new Label("Server:");
404     grid.setConstraints(lbl, gridc);
405     p.add(lbl);
406     gridc.gridwidth = GridBagConstraints.REMAINDER;
407     gridc.weightx   = 1.0;
408     textSrv = new TextField("", 16);
409     grid.setConstraints(textSrv, gridc);
410     p.add(textSrv);
411       }
412 
413       gridc.gridy += 1;
414       gridc.gridwidth = 1;
415       gridc.weightx   = 0;
416       lbl = new Label("Username:");
417       grid.setConstraints(lbl, gridc);
418       p.add(lbl);
419       gridc.gridwidth = GridBagConstraints.REMAINDER;
420       gridc.weightx   = 1.0;
421       textUser = new TextField("", 16);
422       grid.setConstraints(textUser, gridc);
423       p.add(textUser);
424 
425       gridc.gridy += 1;
426       gridc.gridwidth = 1;
427       gridc.weightx   = 0;
428       lbl = new Label("Password:");
429       grid.setConstraints(lbl, gridc);
430       p.add(lbl);
431       gridc.gridwidth = GridBagConstraints.REMAINDER;
432       gridc.weightx   = 1.0;
433       textPasswd = new TextField("", 16);
434       textPasswd.setEchoChar('*');
435       grid.setConstraints(textPasswd, gridc);
436       p.add(textPasswd);
437 
438       if(!haveServer)
439     textSrv.setText(propsHandler.getProperty("server"));
440       textUser.setText(propsHandler.getProperty("usrname"));
441   }
442 
443   al = new ActionListener() {
444       public void actionPerformed(ActionEvent e) {
445     if(e.getActionCommand().equals("Connect")) {
446         if(!listMode) {
447       String srv = "dummy";
448       if(!haveServer) {
449           srv = textSrv.getText();
450       }
451       String usr = textUser.getText();
452       if(srv == null || srv.trim().length() == 0 ||
453          usr == null || usr.trim().length() == 0) {
454              return;
455          }
456         }
457         synchronized(SSHTunnelingClient.this) {
458       SSHTunnelingClient.this.notify();
459         }
460         connBut.setEnabled(false);
461         discBut.requestFocus();
462     } else if(e.getActionCommand().equals("Disconnect")) {
463         forcedDisconnect();
464         discBut.setEnabled(false);
465     } else if(e.getActionCommand().equals("Tunnels Setup")) {
466         SSHTunnelDialog.show("MindTunnel - Basic Tunnels Setup",
467            SSHTunnelingClient.this, propsHandler, parent);
468     } else if(e.getActionCommand().equals("File Transfer")) {
469         SSHSCPDialog.show("MindTunnel - File Transfer", parent,
470               propsHandler, SSHTunnelingClient.this);
471     } else if(e.getActionCommand().equals("Configure Proxy")) {
472         SSHProxyDialog.show("MindTunnel - Proxy Settings", parent,
473           propsHandler);
474     }
475       }
476   };
477 
478   Panel bp;
479 
480   if(haveTunnelDialog || haveSCPDialog || haveProxyDialog) {
481       bp = new Panel(new FlowLayout());
482       if(haveTunnelDialog) {
483     tunnelBut = new Button("Tunnels Setup");
484     tunnelBut.addActionListener(al);
485     bp.add(tunnelBut);
486       }
487       if(haveSCPDialog) {
488     scpBut = new Button("File Transfer");
489     scpBut.addActionListener(al);
490     bp.add(scpBut);
491       }
492       if(haveProxyDialog) {
493     proxyBut = new Button("Configure Proxy");
494     proxyBut.addActionListener(al);
495     bp.add(proxyBut);
496       }
497       gridc.gridy += 1;
498       gridc.gridwidth = GridBagConstraints.REMAINDER;
499       gridc.anchor    = GridBagConstraints.CENTER;
500       grid.setConstraints(bp, gridc);
501       p.add(bp);
502   }
503 
504   bp = new Panel(new FlowLayout());
505   bp.add(connBut = new Button("Connect"));
506 
507   connBut.addActionListener(al);
508 
509   bp.add(discBut = new Button("Disconnect"));
510   discBut.addActionListener(al);
511 
512   gridc.gridy += 1;
513   gridc.gridwidth = GridBagConstraints.REMAINDER;
514   gridc.anchor    = GridBagConstraints.CENTER;
515   grid.setConstraints(bp, gridc);
516   p.add(bp);
517 
518   grid  = new GridBagLayout();
519   gridc = new GridBagConstraints();
520 
521   parent.setLayout(grid);
522 
523   gridc.insets    = new Insets(4, 4, 4, 4);
524   gridc.gridy     = 0;
525   gridc.gridwidth = GridBagConstraints.REMAINDER;
526   gridc.fill      = GridBagConstraints.HORIZONTAL;
527   gridc.weightx   = 1.0;
528   gridc.anchor    = GridBagConstraints.CENTER;
529 
530   Image logoImg = getLogo();
531   if(logoImg != null) {
532       Logo logo = new Logo(logoImg);
533       switch(logoPlacement) {
534       case GridBagConstraints.NORTH:
535     gridc.fill = GridBagConstraints.NONE;
536     grid.setConstraints(logo, gridc);
537     parent.add(logo);
538     gridc.fill  = GridBagConstraints.HORIZONTAL;
539     gridc.gridy = 1;
540     grid.setConstraints(p, gridc);
541     parent.add(p);
542     break;
543 
544       case GridBagConstraints.WEST:
545     gridc.fill = GridBagConstraints.NONE;
546     gridc.gridwidth = 1;
547     grid.setConstraints(logo, gridc);
548     parent.add(logo);
549     gridc.fill      = GridBagConstraints.HORIZONTAL;
550     gridc.gridwidth = GridBagConstraints.REMAINDER;
551     grid.setConstraints(p, gridc);
552     parent.add(p);
553     break;
554 
555       case GridBagConstraints.EAST:
556     gridc.gridwidth = 1;
557     grid.setConstraints(p, gridc);
558     parent.add(p);
559     gridc.fill      = GridBagConstraints.NONE;
560     gridc.gridwidth = GridBagConstraints.REMAINDER;
561     grid.setConstraints(logo, gridc);
562     parent.add(logo);
563     break;
564 
565       case GridBagConstraints.SOUTH:
566     grid.setConstraints(p, gridc);
567     parent.add(p);
568     gridc.gridy = 1;
569     gridc.fill  = GridBagConstraints.NONE;
570     grid.setConstraints(logo, gridc);
571     parent.add(logo);
572     break;
573       }
574   } else {
575       grid.setConstraints(p, gridc);
576       parent.add(p);
577   }
578 
579   AWTConvenience.setKeyListenerOfChildren(parent,
580             new AWTConvenience.OKCancelAdapter(connBut, discBut),
581             null);
582 
583   AWTConvenience.setBackgroundOfChildren(parent);
584 
585   parent.pack();
586   parent.show();
587     }
588 
589     Image getLogo() {
590   InputStream is;
591   ByteArrayOutputStream baos;
592   Image logo = null;
593 
594   if((is = this.getClass().getResourceAsStream("/images/logo_top.gif")) != null) {
595       logoPlacement = GridBagConstraints.NORTH;
596   } else if((is = this.getClass().getResourceAsStream("/images/logo_left.gif")) != null) {
597       logoPlacement = GridBagConstraints.WEST;
598   } else if((is = this.getClass().getResourceAsStream("/images/logo_right.gif")) != null) {
599       logoPlacement = GridBagConstraints.EAST;
600   } else if((is = this.getClass().getResourceAsStream("/images/logo_bottom.gif")) != null) {
601       logoPlacement = GridBagConstraints.SOUTH;
602   } else {
603       return null;
604   }
605 
606   baos = new ByteArrayOutputStream();
607   try {
608       int c;
609       while((c = is.read()) >= 0)
610     baos.write(c);
611       logo = Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
612   } catch(IOException e) {
613       // !!!
614   }
615 
616   return logo;
617     }
618 
619     public final boolean confirmDialog(String message, boolean defAnswer) {
620   return SSHMiscDialogs.confirm("MindTunnel - Confirmation", message, true,
621               parent);
622     }
623 
624     public final void alertDialog(String message) {
625   SSHMiscDialogs.alert("MindTunnel - Alert", message, parent);
626     }
627 
628     public final String passwordDialog(String message, String title) {
629   return SSHMiscDialogs.password(title, message, parent);
630     }
631 
632 }