Skip to content

Commit c4a0688

Browse files
george-hopkinsEugeny
authored andcommitted
Add method to read known host key
1 parent 84072f3 commit c4a0688

File tree

1 file changed

+40
-42
lines changed

1 file changed

+40
-42
lines changed

russh-keys/src/lib.rs

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
use std::borrow::Cow;
6767
use std::fs::{File, OpenOptions};
6868
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write};
69-
use std::path::Path;
69+
use std::path::{Path, PathBuf};
7070

7171
use aes::cipher::block_padding::UnpadError;
7272
use aes::cipher::inout::PadError;
@@ -293,6 +293,11 @@ fn is_base64_char(c: char) -> bool {
293293
|| c == '='
294294
}
295295

296+
/// Record a host's public key into the user's known_hosts file.
297+
pub fn learn_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<(), Error> {
298+
learn_known_hosts_path(host, port, pubkey, known_hosts_path()?)
299+
}
300+
296301
/// Record a host's public key into a nonstandard location.
297302
pub fn learn_known_hosts_path<P: AsRef<Path>>(
298303
host: &str,
@@ -333,17 +338,21 @@ pub fn learn_known_hosts_path<P: AsRef<Path>>(
333338
Ok(())
334339
}
335340

336-
/// Check that a server key matches the one recorded in file `path`.
337-
pub fn check_known_hosts_path<P: AsRef<Path>>(
341+
/// Get the server key that matches the one recorded in the user's known_hosts file.
342+
pub fn known_host_key(host: &str, port: u16) -> Result<Option<(usize, key::PublicKey)>, Error> {
343+
known_host_key_path(host, port, known_hosts_path()?)
344+
}
345+
346+
/// Get the server key that matches the one recorded in `path`.
347+
pub fn known_host_key_path<P: AsRef<Path>>(
338348
host: &str,
339349
port: u16,
340-
pubkey: &key::PublicKey,
341350
path: P,
342-
) -> Result<bool, Error> {
351+
) -> Result<Option<(usize, key::PublicKey)>, Error> {
343352
let mut f = if let Ok(f) = File::open(path) {
344353
BufReader::new(f)
345354
} else {
346-
return Ok(false);
355+
return Ok(None);
347356
};
348357
let mut buffer = String::new();
349358

@@ -368,18 +377,14 @@ pub fn check_known_hosts_path<P: AsRef<Path>>(
368377
if let (Some(h), Some(k)) = (hosts, key) {
369378
debug!("{:?} {:?}", h, k);
370379
if match_hostname(&host_port, h) {
371-
if &parse_public_key_base64(k)? == pubkey {
372-
return Ok(true);
373-
} else {
374-
return Err(Error::KeyChanged { line });
375-
}
380+
return Ok(Some((line, parse_public_key_base64(k)?)));
376381
}
377382
}
378383
}
379384
buffer.clear();
380385
line += 1;
381386
}
382-
Ok(false)
387+
Ok(None)
383388
}
384389

385390
fn match_hostname(host: &str, pattern: &str) -> bool {
@@ -404,49 +409,42 @@ fn match_hostname(host: &str, pattern: &str) -> bool {
404409
false
405410
}
406411

407-
/// Record a host's public key into the user's known_hosts file.
408-
#[cfg(target_os = "windows")]
409-
pub fn learn_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<(), Error> {
410-
if let Some(mut known_host_file) = dirs::home_dir() {
411-
known_host_file.push("ssh");
412-
known_host_file.push("known_hosts");
413-
learn_known_hosts_path(host, port, pubkey, &known_host_file)
414-
} else {
415-
Err(Error::NoHomeDir)
416-
}
412+
/// Check whether the host is known, from its standard location.
413+
pub fn check_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<bool, Error> {
414+
check_known_hosts_path(host, port, pubkey, known_hosts_path()?)
417415
}
418416

419-
/// Record a host's public key into the user's known_hosts file.
420-
#[cfg(not(target_os = "windows"))]
421-
pub fn learn_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<(), Error> {
422-
if let Some(mut known_host_file) = dirs::home_dir() {
423-
known_host_file.push(".ssh");
424-
known_host_file.push("known_hosts");
425-
learn_known_hosts_path(host, port, pubkey, &known_host_file)
417+
/// Check that a server key matches the one recorded in file `path`.
418+
pub fn check_known_hosts_path<P: AsRef<Path>>(
419+
host: &str,
420+
port: u16,
421+
pubkey: &key::PublicKey,
422+
path: P,
423+
) -> Result<bool, Error> {
424+
if let Some((line, recorded)) = known_host_key_path(host, port, path)? {
425+
if recorded == *pubkey {
426+
Ok(true)
427+
} else {
428+
Err(Error::KeyChanged { line })
429+
}
426430
} else {
427-
Err(Error::NoHomeDir)
431+
Ok(false)
428432
}
429433
}
430434

431-
/// Check whether the host is known, from its standard location.
432435
#[cfg(target_os = "windows")]
433-
pub fn check_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<bool, Error> {
434-
if let Some(mut known_host_file) = dirs::home_dir() {
435-
known_host_file.push("ssh");
436-
known_host_file.push("known_hosts");
437-
check_known_hosts_path(host, port, pubkey, &known_host_file)
436+
fn known_hosts_path() -> Result<PathBuf, Error> {
437+
if let Some(home_dir) = dirs::home_dir() {
438+
Ok(home_dir.join("ssh").join("known_hosts"))
438439
} else {
439440
Err(Error::NoHomeDir)
440441
}
441442
}
442443

443-
/// Check whether the host is known, from its standard location.
444444
#[cfg(not(target_os = "windows"))]
445-
pub fn check_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<bool, Error> {
446-
if let Some(mut known_host_file) = dirs::home_dir() {
447-
known_host_file.push(".ssh");
448-
known_host_file.push("known_hosts");
449-
check_known_hosts_path(host, port, pubkey, &known_host_file)
445+
fn known_hosts_path() -> Result<PathBuf, Error> {
446+
if let Some(home_dir) = dirs::home_dir() {
447+
Ok(home_dir.join(".ssh").join("known_hosts"))
450448
} else {
451449
Err(Error::NoHomeDir)
452450
}

0 commit comments

Comments
 (0)