00001 using System;
00002 using System.IO;
00003
00004 namespace Tamir.SharpSsh.jsch
00005 {
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 public class KnownHosts : HostKeyRepository
00036 {
00037 private const String _known_hosts="known_hosts";
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 private JSch jsch=null;
00051 private String known_hosts=null;
00052 private System.Collections.ArrayList pool=null;
00053
00054 internal KnownHosts(JSch jsch) : base()
00055 {
00056 this.jsch=jsch;
00057 pool=new System.Collections.ArrayList();
00058 }
00059
00060 internal void setKnownHosts(String foo)
00061 {
00062 try
00063 {
00064 known_hosts=foo;
00065 FileStream fis=File.OpenRead(foo);
00066 setKnownHosts( new StreamReader(fis) );
00067 }
00068 catch
00069 {
00070 }
00071 }
00072 internal void setKnownHosts(StreamReader foo)
00073 {
00074 pool.Clear();
00075 System.Text.StringBuilder sb=new System.Text.StringBuilder();
00076 byte i;
00077 int j;
00078 bool error=false;
00079 try
00080 {
00081 StreamReader fis=foo;
00082 String host;
00083 String key=null;
00084 int type;
00085 byte[] buf=new byte[1024];
00086 int bufl=0;
00087 loop:
00088 while(true)
00089 {
00090 bufl=0;
00091 while(true)
00092 {
00093 j=fis.Read();
00094 if(j==-1){ goto break_loop;}
00095 if(j==0x0d){ continue; }
00096 if(j==0x0a){ break; }
00097 buf[bufl++]=(byte)j;
00098 }
00099
00100 j=0;
00101 while(j<bufl)
00102 {
00103 i=buf[j];
00104 if(i==' '||i=='\t'){ j++; continue; }
00105 if(i=='#')
00106 {
00107 addInvalidLine(System.Text.Encoding.Default.GetString(buf, 0, bufl));
00108 goto loop;
00109 }
00110 break;
00111 }
00112 if(j>=bufl)
00113 {
00114 addInvalidLine(System.Text.Encoding.Default.GetString(buf, 0, bufl));
00115 goto loop;
00116 }
00117
00118 sb.Length = 0;
00119 while(j<bufl)
00120 {
00121 i=buf[j++];
00122 if(i==0x20 || i=='\t'){ break; }
00123 sb.Append((char)i);
00124 }
00125 host=sb.ToString();
00126 if(j>=bufl || host.Length==0)
00127 {
00128 addInvalidLine(System.Text.Encoding.Default.GetString(buf, 0, bufl));
00129 goto loop;
00130 }
00131
00132 sb.Length=0;
00133 type=-1;
00134 while(j<bufl)
00135 {
00136 i=buf[j++];
00137 if(i==0x20 || i=='\t'){ break; }
00138 sb.Append((char)i);
00139 }
00140 if(sb.ToString().Equals("ssh-dss")){ type=HostKey.SSHDSS; }
00141 else if(sb.ToString().Equals("ssh-rsa")){ type=HostKey.SSHRSA; }
00142 else { j=bufl; }
00143 if(j>=bufl)
00144 {
00145 addInvalidLine(Util.getString(buf, 0, bufl));
00146 goto loop;
00147 }
00148
00149 sb.Length=0;
00150 while(j<bufl)
00151 {
00152 i=buf[j++];
00153 if(i==0x0d){ continue; }
00154 if(i==0x0a){ break; }
00155 sb.Append((char)i);
00156 }
00157 key=sb.ToString();
00158 if(key.Length==0)
00159 {
00160 addInvalidLine(Util.getString(buf, 0, bufl));
00161 goto loop;
00162 }
00163
00164
00165
00166
00167 HostKey hk = new HostKey(host, type,
00168 Util.fromBase64(Util.getBytes(key), 0,
00169 key.Length));
00170 pool.Add(hk);
00171 }
00172
00173 break_loop:
00174
00175 fis.Close();
00176 if(error)
00177 {
00178 throw new JSchException("KnownHosts: invalid format");
00179 }
00180 }
00181 catch(Exception e)
00182 {
00183 if(e is JSchException)
00184 {
00185 throw (JSchException)e;
00186 }
00187 throw new JSchException(e.ToString());
00188 }
00189 }
00190 private void addInvalidLine(String line)
00191 {
00192 HostKey hk = new HostKey(line, HostKey.UNKNOWN, null);
00193 pool.Add(hk);
00194 }
00195 String getKnownHostsFile(){ return known_hosts; }
00196 public override String getKnownHostsRepositoryID(){ return known_hosts; }
00197
00198 public override int check(String host, byte[] key)
00199 {
00200
00201
00202 HostKey hk;
00203 int result=NOT_INCLUDED;
00204 int type=getType(key);
00205 for(int i=0; i<pool.Count; i++)
00206 {
00207 hk=(HostKey)(pool[i]);
00208 if(isIncluded(hk.host, host) && hk.type==type)
00209 {
00210 if(Util.array_equals(hk.key, key))
00211 {
00212
00213 return OK;
00214 }
00215 else
00216 {
00217 result=CHANGED;
00218 }
00219 }
00220 }
00221
00222 return result;
00223 }
00224 public override void add(String host, byte[] key, UserInfo userinfo)
00225 {
00226 HostKey hk;
00227 int type=getType(key);
00228 for(int i=0; i<pool.Count; i++)
00229 {
00230 hk=(HostKey)(pool[i]);
00231 if(isIncluded(hk.host, host) && hk.type==type)
00232 {
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 }
00245 }
00246 hk=new HostKey(host, type, key);
00247 pool.Add(hk);
00248
00249 String bar=getKnownHostsRepositoryID();
00250 if(userinfo!=null &&
00251 bar!=null)
00252 {
00253 bool foo=true;
00254 FileInfo goo=new FileInfo(bar);
00255 if(!goo.Exists)
00256 {
00257 foo=false;
00258 if(userinfo!=null)
00259 {
00260 foo=userinfo.promptYesNo(
00261 bar+" does not exist.\n"+
00262 "Are you sure you want to create it?"
00263 );
00264 DirectoryInfo dir =goo.Directory;
00265 if(foo && dir!=null && !dir.Exists)
00266 {
00267 foo=userinfo.promptYesNo(
00268 "The parent directory "+dir.Name+" does not exist.\n"+
00269 "Are you sure you want to create it?"
00270 );
00271 if(foo)
00272 {
00273 try{dir.Create(); userinfo.showMessage(dir.Name+" has been succesfully created.\nPlease check its access permission.");}
00274 catch
00275 {
00276 userinfo.showMessage(dir.Name+" has not been created.");
00277 foo=false;
00278 }
00279 }
00280 }
00281 if(goo==null)foo=false;
00282 }
00283 }
00284 if(foo)
00285 {
00286 try
00287 {
00288 sync(bar);
00289 }
00290 catch(Exception e){ Console.WriteLine("sync known_hosts: "+e); }
00291 }
00292 }
00293 }
00294
00295 public override HostKey[] getHostKey()
00296 {
00297 return getHostKey(null, null);
00298 }
00299 public override HostKey[] getHostKey(String host, String type)
00300 {
00301 lock(pool)
00302 {
00303 int count=0;
00304 for(int i=0; i<pool.Count; i++)
00305 {
00306 HostKey hk=(HostKey)pool[i];
00307 if(hk.type==HostKey.UNKNOWN) continue;
00308 if(host==null ||
00309 (isIncluded(hk.host, host) &&
00310 (type==null || hk.getType().Equals(type))))
00311 {
00312 count++;
00313 }
00314 }
00315 if(count==0)return null;
00316 HostKey[] foo=new HostKey[count];
00317 int j=0;
00318 for(int i=0; i<pool.Count; i++)
00319 {
00320 HostKey hk=(HostKey)pool[i];
00321 if(hk.type==HostKey.UNKNOWN) continue;
00322 if(host==null ||
00323 (isIncluded(hk.host, host) &&
00324 (type==null || hk.getType().Equals(type))))
00325 {
00326 foo[j++]=hk;
00327 }
00328 }
00329 return foo;
00330 }
00331 }
00332 public override void remove(String host, String type)
00333 {
00334 remove(host, type, null);
00335 }
00336 public override void remove(String host, String type, byte[] key)
00337 {
00338 bool _sync=false;
00339 for(int i=0; i<pool.Count; i++)
00340 {
00341 HostKey hk=(HostKey)(pool[i]);
00342 if(host==null ||
00343 (hk.getHost().Equals(host) &&
00344 (type==null || (hk.getType().Equals(type) &&
00345 (key==null || Util.array_equals(key, hk.key))))))
00346 {
00347 pool.Remove(hk);
00348 _sync=true;
00349 }
00350 }
00351 if(_sync)
00352 {
00353 try{sync();}
00354 catch{};
00355 }
00356 }
00357
00358 private void sync()
00359 {
00360 if(known_hosts!=null)
00361 sync(known_hosts);
00362 }
00363 private void sync(String foo)
00364 {
00365 if(foo==null) return;
00366 FileStream fos=File.OpenWrite(foo);
00367 dump(fos);
00368 fos.Close();
00369 }
00370
00371 private static byte[] space= new byte[]{(byte)0x20};
00372 private static byte[] cr= System.Text.Encoding.Default.GetBytes("\n");
00373 void dump(FileStream outs)
00374 {
00375
00376 try
00377 {
00378 HostKey hk;
00379 for(int i=0; i<pool.Count; i++)
00380 {
00381 hk=(HostKey)(pool[i]);
00382
00383 String host=hk.getHost();
00384 String type=hk.getType();
00385 if(type.Equals("UNKNOWN"))
00386 {
00387 Write(outs, Util.getBytes(host));
00388 Write(outs, cr);
00389 continue;
00390 }
00391 Write(outs, Util.getBytes(host));
00392 Write(outs, space);
00393 Write(outs, Util.getBytes(type));
00394 Write(outs, space);
00395 Write(outs, Util.getBytes(hk.getKey()));
00396 Write(outs, cr);
00397 }
00398 outs.Flush();
00399 }
00400 catch(Exception e)
00401 {
00402 Console.WriteLine(e);
00403 }
00404 }
00405
00406 private void Write(Stream s, byte[] buff)
00407 {
00408 s.Write(buff, 0, buff.Length);
00409 }
00410 private int getType(byte[] key)
00411 {
00412 if(key[8]=='d') return HostKey.SSHDSS;
00413 if(key[8]=='r') return HostKey.SSHRSA;
00414 return HostKey.UNKNOWN;
00415 }
00416 private String deleteSubString(String hosts, String host)
00417 {
00418 int i=0;
00419 int hostlen=host.Length;
00420 int hostslen=hosts.Length;
00421 int j;
00422 while(i<hostslen)
00423 {
00424 j=hosts.IndexOf(',', i);
00425 if(j==-1) break;
00426 if(!host.Equals(hosts.Substring(i, j)))
00427 {
00428 i=j+1;
00429 continue;
00430 }
00431 return hosts.Substring(0, i)+hosts.Substring(j+1);
00432 }
00433 if(hosts.EndsWith(host) && hostslen-i==hostlen)
00434 {
00435 return hosts.Substring(0, (hostlen==hostslen) ? 0 :hostslen-hostlen-1);
00436 }
00437 return hosts;
00438 }
00439 private bool isIncluded(String hosts, String host)
00440 {
00441 int i=0;
00442 int hostlen=host.Length;
00443 int hostslen=hosts.Length;
00444 int j;
00445 while(i<hostslen)
00446 {
00447 j=hosts.IndexOf(',', i);
00448 if(j==-1)
00449 {
00450 if(hostlen!=hostslen-i) return false;
00451 return Util.regionMatches( hosts, true, i, host, 0, hostlen);
00452
00453 }
00454 if(hostlen==(j-i))
00455 {
00456 if(Util.regionMatches( hosts,true, i, host, 0, hostlen)) return true;
00457
00458 }
00459 i=j+1;
00460 }
00461 return false;
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 }
00522
00523 }