KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcraft > jsch > KnownHosts


1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
2 /*
3 Copyright (c) 2002,2003,2004,2005,2006 ymnk, JCraft,Inc. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8   1. Redistributions of source code must retain the above copyright notice,
9      this list of conditions and the following disclaimer.
10
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in
13      the documentation and/or other materials provided with the distribution.
14
15   3. The names of the authors may not be used to endorse or promote products
16      derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */

29
30 package com.jcraft.jsch;
31
32 import java.io.*;
33
34 public
35 class KnownHosts implements HostKeyRepository{
36   private static final String JavaDoc _known_hosts="known_hosts";
37
38   /*
39   static final int SSHDSS=0;
40   static final int SSHRSA=1;
41   static final int UNKNOWN=2;
42   */

43
44   private JSch jsch=null;
45   private String JavaDoc known_hosts=null;
46   private java.util.Vector JavaDoc pool=null;
47
48   private MAC hmacsha1=null;
49
50   KnownHosts(JSch jsch){
51     super();
52     this.jsch=jsch;
53     pool=new java.util.Vector JavaDoc();
54   }
55
56   void setKnownHosts(String JavaDoc foo) throws JSchException{
57     try{
58       known_hosts=foo;
59       FileInputStream fis=new FileInputStream(foo);
60       setKnownHosts(fis);
61     }
62     catch(FileNotFoundException e){
63     }
64   }
65   void setKnownHosts(InputStream foo) throws JSchException{
66     pool.removeAllElements();
67     StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
68     byte i;
69     int j;
70     boolean error=false;
71     try{
72       InputStream fis=foo;
73       String JavaDoc host;
74       String JavaDoc key=null;
75       int type;
76       byte[] buf=new byte[1024];
77       int bufl=0;
78 loop:
79       while(true){
80     bufl=0;
81         while(true){
82           j=fis.read();
83           if(j==-1){
84             if(bufl==0){ break loop; }
85             else{ break; }
86           }
87       if(j==0x0d){ continue; }
88       if(j==0x0a){ break; }
89           if(buf.length<=bufl){
90             if(bufl>1024*10) break; // too long...
91
byte[] newbuf=new byte[buf.length*2];
92             System.arraycopy(buf, 0, newbuf, 0, buf.length);
93             buf=newbuf;
94           }
95           buf[bufl++]=(byte)j;
96     }
97
98     j=0;
99         while(j<bufl){
100           i=buf[j];
101       if(i==' '||i=='\t'){ j++; continue; }
102       if(i=='#'){
103         addInvalidLine(new String JavaDoc(buf, 0, bufl));
104         continue loop;
105       }
106       break;
107     }
108     if(j>=bufl){
109       addInvalidLine(new String JavaDoc(buf, 0, bufl));
110       continue loop;
111     }
112
113         sb.setLength(0);
114         while(j<bufl){
115           i=buf[j++];
116           if(i==0x20 || i=='\t'){ break; }
117           sb.append((char)i);
118     }
119     host=sb.toString();
120     if(j>=bufl || host.length()==0){
121       addInvalidLine(new String JavaDoc(buf, 0, bufl));
122       continue loop;
123     }
124
125         sb.setLength(0);
126     type=-1;
127         while(j<bufl){
128           i=buf[j++];
129           if(i==0x20 || i=='\t'){ break; }
130           sb.append((char)i);
131     }
132     if(sb.toString().equals("ssh-dss")){ type=HostKey.SSHDSS; }
133     else if(sb.toString().equals("ssh-rsa")){ type=HostKey.SSHRSA; }
134     else { j=bufl; }
135     if(j>=bufl){
136       addInvalidLine(new String JavaDoc(buf, 0, bufl));
137       continue loop;
138     }
139
140         sb.setLength(0);
141         while(j<bufl){
142           i=buf[j++];
143           if(i==0x0d){ continue; }
144           if(i==0x0a){ break; }
145           sb.append((char)i);
146     }
147     key=sb.toString();
148     if(key.length()==0){
149       addInvalidLine(new String JavaDoc(buf, 0, bufl));
150       continue loop;
151     }
152
153     //System.err.println(host);
154
//System.err.println("|"+key+"|");
155

156     HostKey hk = null;
157         hk = new HashedHostKey(host, type,
158                                Util.fromBase64(key.getBytes(), 0,
159                                                key.length()));
160     pool.addElement(hk);
161       }
162       fis.close();
163       if(error){
164     throw new JSchException("KnownHosts: invalid format");
165       }
166     }
167     catch(Exception JavaDoc e){
168       if(e instanceof JSchException)
169     throw (JSchException)e;
170       if(e instanceof Throwable JavaDoc)
171         throw new JSchException(e.toString(), (Throwable JavaDoc)e);
172       throw new JSchException(e.toString());
173     }
174   }
175   private void addInvalidLine(String JavaDoc line) throws JSchException {
176     HostKey hk = new HostKey(line, HostKey.UNKNOWN, null);
177     pool.addElement(hk);
178   }
179   String JavaDoc getKnownHostsFile(){ return known_hosts; }
180   public String JavaDoc getKnownHostsRepositoryID(){ return known_hosts; }
181
182   public int check(String JavaDoc host, byte[] key){
183     int result=NOT_INCLUDED;
184     if(host==null){
185       return result;
186     }
187
188     int type=getType(key);
189     HostKey hk;
190
191     synchronized(pool){
192     for(int i=0; i<pool.size(); i++){
193       hk=(HostKey)(pool.elementAt(i));
194       if(hk.isMatched(host) && hk.type==type){
195         if(Util.array_equals(hk.key, key)){
196       //System.err.println("find!!");
197
return OK;
198     }
199     else{
200           result=CHANGED;
201     }
202       }
203     }
204     }
205     //System.err.println("fail!!");
206
return result;
207   }
208   public void add(HostKey hostkey, UserInfo userinfo){
209     int type=hostkey.type;
210     String JavaDoc host=hostkey.getHost();
211     byte[] key=hostkey.key;
212
213     HostKey hk=null;
214     synchronized(pool){
215       for(int i=0; i<pool.size(); i++){
216         hk=(HostKey)(pool.elementAt(i));
217         if(hk.isMatched(host) && hk.type==type){
218 /*
219       if(Util.array_equals(hk.key, key)){ return; }
220       if(hk.host.equals(host)){
221         hk.key=key;
222         return;
223       }
224       else{
225         hk.host=deleteSubString(hk.host, host);
226         break;
227       }
228 */

229         }
230       }
231     }
232
233     hk=hostkey;
234
235     pool.addElement(hk);
236
237     String JavaDoc bar=getKnownHostsRepositoryID();
238     if(bar!=null){
239       boolean foo=true;
240       File goo=new File(bar);
241       if(!goo.exists()){
242         foo=false;
243         if(userinfo!=null){
244           foo=userinfo.promptYesNo(bar+" does not exist.\n"+
245                                    "Are you sure you want to create it?"
246                                    );
247           goo=goo.getParentFile();
248           if(foo && goo!=null && !goo.exists()){
249             foo=userinfo.promptYesNo("The parent directory "+goo+" does not exist.\n"+
250                                      "Are you sure you want to create it?"
251                                      );
252             if(foo){
253               if(!goo.mkdirs()){
254                 userinfo.showMessage(goo+" has not been created.");
255                 foo=false;
256               }
257               else{
258                 userinfo.showMessage(goo+" has been succesfully created.\nPlease check its access permission.");
259               }
260             }
261           }
262           if(goo==null)foo=false;
263         }
264       }
265       if(foo){
266         try{
267           sync(bar);
268         }
269         catch(Exception JavaDoc e){ System.err.println("sync known_hosts: "+e); }
270       }
271     }
272   }
273
274   public HostKey[] getHostKey(){
275     return getHostKey(null, null);
276   }
277   public HostKey[] getHostKey(String JavaDoc host, String JavaDoc type){
278     synchronized(pool){
279       int count=0;
280       for(int i=0; i<pool.size(); i++){
281     HostKey hk=(HostKey)pool.elementAt(i);
282     if(hk.type==HostKey.UNKNOWN) continue;
283     if(host==null ||
284        (hk.isMatched(host) &&
285         (type==null || hk.getType().equals(type)))){
286       count++;
287     }
288       }
289       if(count==0)return null;
290       HostKey[] foo=new HostKey[count];
291       int j=0;
292       for(int i=0; i<pool.size(); i++){
293     HostKey hk=(HostKey)pool.elementAt(i);
294     if(hk.type==HostKey.UNKNOWN) continue;
295     if(host==null ||
296        (hk.isMatched(host) &&
297         (type==null || hk.getType().equals(type)))){
298       foo[j++]=hk;
299     }
300       }
301       return foo;
302     }
303   }
304   public void remove(String JavaDoc host, String JavaDoc type){
305     remove(host, type, null);
306   }
307   public void remove(String JavaDoc host, String JavaDoc type, byte[] key){
308     boolean sync=false;
309     synchronized(pool){
310     for(int i=0; i<pool.size(); i++){
311       HostKey hk=(HostKey)(pool.elementAt(i));
312       if(host==null ||
313      (hk.isMatched(host) &&
314       (type==null || (hk.getType().equals(type) &&
315               (key==null || Util.array_equals(key, hk.key)))))){
316         String JavaDoc hosts=hk.getHost();
317         if(hosts.equals(host) ||
318            ((hk instanceof HashedHostKey) &&
319             ((HashedHostKey)hk).isHashed())){
320           pool.removeElement(hk);
321         }
322         else{
323           hk.host=deleteSubString(hosts, host);
324         }
325     sync=true;
326       }
327     }
328     }
329     if(sync){
330       try{sync();}catch(Exception JavaDoc e){};
331     }
332   }
333
334   protected void sync() throws IOException {
335     if(known_hosts!=null)
336       sync(known_hosts);
337   }
338   protected synchronized void sync(String JavaDoc foo) throws IOException {
339     if(foo==null) return;
340     FileOutputStream fos=new FileOutputStream(foo);
341     dump(fos);
342     fos.close();
343   }
344
345   private static final byte[] space={(byte)0x20};
346   private static final byte[] cr="\n".getBytes();
347   void dump(OutputStream out) throws IOException {
348     try{
349       HostKey hk;
350       synchronized(pool){
351       for(int i=0; i<pool.size(); i++){
352         hk=(HostKey)(pool.elementAt(i));
353         //hk.dump(out);
354
String JavaDoc host=hk.getHost();
355     String JavaDoc type=hk.getType();
356     if(type.equals("UNKNOWN")){
357       out.write(host.getBytes());
358       out.write(cr);
359       continue;
360     }
361     out.write(host.getBytes());
362     out.write(space);
363     out.write(type.getBytes());
364     out.write(space);
365     out.write(hk.getKey().getBytes());
366     out.write(cr);
367       }
368       }
369     }
370     catch(Exception JavaDoc e){
371       System.err.println(e);
372     }
373   }
374   private int getType(byte[] key){
375     if(key[8]=='d') return HostKey.SSHDSS;
376     if(key[8]=='r') return HostKey.SSHRSA;
377     return HostKey.UNKNOWN;
378   }
379   private String JavaDoc deleteSubString(String JavaDoc hosts, String JavaDoc host){
380     int i=0;
381     int hostlen=host.length();
382     int hostslen=hosts.length();
383     int j;
384     while(i<hostslen){
385       j=hosts.indexOf(',', i);
386       if(j==-1) break;
387       if(!host.equals(hosts.substring(i, j))){
388         i=j+1;
389         continue;
390       }
391       return hosts.substring(0, i)+hosts.substring(j+1);
392     }
393     if(hosts.endsWith(host) && hostslen-i==hostlen){
394       return hosts.substring(0, (hostlen==hostslen) ? 0 :hostslen-hostlen-1);
395     }
396     return hosts;
397   }
398
399   private synchronized MAC getHMACSHA1(){
400     if(hmacsha1==null){
401       try{
402         Class JavaDoc c=Class.forName(jsch.getConfig("hmac-sha1"));
403         hmacsha1=(MAC)(c.newInstance());
404       }
405       catch(Exception JavaDoc e){
406         System.err.println("hmacsha1: "+e);
407       }
408     }
409     return hmacsha1;
410   }
411
412   HostKey createHashedHostKey(String JavaDoc host, byte[]key) throws JSchException {
413     HashedHostKey hhk=new HashedHostKey(host, key);
414     hhk.hash();
415     return hhk;
416   }
417   class HashedHostKey extends HostKey{
418     private static final String JavaDoc HASH_MAGIC="|1|";
419     private static final String JavaDoc HASH_DELIM="|";
420
421     private boolean hashed=false;
422     byte[] salt=null;
423     byte[] hash=null;
424
425
426     HashedHostKey(String JavaDoc host, byte[] key) throws JSchException {
427       this(host, GUESS, key);
428     }
429     HashedHostKey(String JavaDoc host, int type, byte[] key) throws JSchException {
430       super(host, type, key);
431       if(this.host.startsWith(HASH_MAGIC) &&
432          this.host.substring(HASH_MAGIC.length()).indexOf(HASH_DELIM)>0){
433         String JavaDoc data=this.host.substring(HASH_MAGIC.length());
434         String JavaDoc _salt=data.substring(0, data.indexOf(HASH_DELIM));
435         String JavaDoc _hash=data.substring(data.indexOf(HASH_DELIM)+1);
436         salt=Util.fromBase64(_salt.getBytes(), 0, _salt.length());
437         hash=Util.fromBase64(_hash.getBytes(), 0, _hash.length());
438         if(salt.length!=20 || // block size of hmac-sha1
439
hash.length!=20){
440           salt=null;
441           hash=null;
442           return;
443         }
444         hashed=true;
445       }
446     }
447
448     boolean isMatched(String JavaDoc _host){
449       if(!hashed){
450         return super.isMatched(_host);
451       }
452       MAC macsha1=getHMACSHA1();
453       try{
454         synchronized(macsha1){
455           macsha1.init(salt);
456           byte[] foo=_host.getBytes();
457           macsha1.update(foo, 0, foo.length);
458           byte[] bar=new byte[macsha1.getBlockSize()];
459           macsha1.doFinal(bar, 0);
460           return Util.array_equals(hash, bar);
461         }
462       }
463       catch(Exception JavaDoc e){
464         System.out.println(e);
465       }
466       return false;
467     }
468
469     boolean isHashed(){
470       return hashed;
471     }
472
473     void hash(){
474       if(hashed)
475         return;
476       MAC macsha1=getHMACSHA1();
477       if(salt==null){
478         Random random=Session.random;
479         synchronized(random){
480           salt=new byte[macsha1.getBlockSize()];
481           random.fill(salt, 0, salt.length);
482         }
483       }
484       try{
485         synchronized(macsha1){
486           macsha1.init(salt);
487           byte[] foo=host.getBytes();
488           macsha1.update(foo, 0, foo.length);
489           hash=new byte[macsha1.getBlockSize()];
490           macsha1.doFinal(hash, 0);
491         }
492       }
493       catch(Exception JavaDoc e){
494       }
495       host=HASH_MAGIC+new String JavaDoc(Util.toBase64(salt, 0, salt.length))+
496         HASH_DELIM+new String JavaDoc(Util.toBase64(hash, 0, hash.length));
497       hashed=true;
498     }
499   }
500 }
501
Popular Tags