1 2 29 30 package com.jcraft.jsch; 31 32 import java.io.*; 33 34 public 35 class KnownHosts implements HostKeyRepository{ 36 private static final String _known_hosts="known_hosts"; 37 38 43 44 private JSch jsch=null; 45 private String known_hosts=null; 46 private java.util.Vector 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 (); 54 } 55 56 void setKnownHosts(String 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 sb=new StringBuffer (); 68 byte i; 69 int j; 70 boolean error=false; 71 try{ 72 InputStream fis=foo; 73 String host; 74 String 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; 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 (buf, 0, bufl)); 104 continue loop; 105 } 106 break; 107 } 108 if(j>=bufl){ 109 addInvalidLine(new String (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 (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 (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 (buf, 0, bufl)); 150 continue loop; 151 } 152 153 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 e){ 168 if(e instanceof JSchException) 169 throw (JSchException)e; 170 if(e instanceof Throwable ) 171 throw new JSchException(e.toString(), (Throwable )e); 172 throw new JSchException(e.toString()); 173 } 174 } 175 private void addInvalidLine(String line) throws JSchException { 176 HostKey hk = new HostKey(line, HostKey.UNKNOWN, null); 177 pool.addElement(hk); 178 } 179 String getKnownHostsFile(){ return known_hosts; } 180 public String getKnownHostsRepositoryID(){ return known_hosts; } 181 182 public int check(String 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 return OK; 198 } 199 else{ 200 result=CHANGED; 201 } 202 } 203 } 204 } 205 return result; 207 } 208 public void add(HostKey hostkey, UserInfo userinfo){ 209 int type=hostkey.type; 210 String 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 229 } 230 } 231 } 232 233 hk=hostkey; 234 235 pool.addElement(hk); 236 237 String 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 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 host, String 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 host, String type){ 305 remove(host, type, null); 306 } 307 public void remove(String host, String 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 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 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 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 String host=hk.getHost(); 355 String 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 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 deleteSubString(String hosts, String 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 c=Class.forName(jsch.getConfig("hmac-sha1")); 403 hmacsha1=(MAC)(c.newInstance()); 404 } 405 catch(Exception e){ 406 System.err.println("hmacsha1: "+e); 407 } 408 } 409 return hmacsha1; 410 } 411 412 HostKey createHashedHostKey(String 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 HASH_MAGIC="|1|"; 419 private static final String HASH_DELIM="|"; 420 421 private boolean hashed=false; 422 byte[] salt=null; 423 byte[] hash=null; 424 425 426 HashedHostKey(String host, byte[] key) throws JSchException { 427 this(host, GUESS, key); 428 } 429 HashedHostKey(String 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 data=this.host.substring(HASH_MAGIC.length()); 434 String _salt=data.substring(0, data.indexOf(HASH_DELIM)); 435 String _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 || hash.length!=20){ 440 salt=null; 441 hash=null; 442 return; 443 } 444 hashed=true; 445 } 446 } 447 448 boolean isMatched(String _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 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 e){ 494 } 495 host=HASH_MAGIC+new String (Util.toBase64(salt, 0, salt.length))+ 496 HASH_DELIM+new String (Util.toBase64(hash, 0, hash.length)); 497 hashed=true; 498 } 499 } 500 } 501 | Popular Tags |