Clean up code, add link to etc-passwd crate

This commit is contained in:
Michael Pfaff 2023-08-08 20:45:52 -04:00
parent 0e48e930ba
commit cc71f5bb9a
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
5 changed files with 298 additions and 302 deletions

478
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -180,7 +180,8 @@ pub async fn client_authenticate(
}
Question::Prompt {
prompt,
echo,
// TODO: implement this
echo: _,
} => {
stdout.write_all(prompt.to_bytes()).await?;
stdout.write_all(b" ").await?;

View File

@ -41,15 +41,22 @@ async fn server_authorize_key(user_id: Uid, public_key: &ssh_key::public::Public
let mut authorized_keys = String::with_capacity(home.len() + PATH.len());
authorized_keys.push_str(home);
authorized_keys.push_str(PATH);
let authorized_keys = tokio::fs::read_to_string(authorized_keys).await?;
let mut authorized_keys = ssh_key::authorized_keys::AuthorizedKeys::new(&authorized_keys);
match tokio::fs::read_to_string(&authorized_keys).await {
Ok(authorized_keys) => {
let mut authorized_keys = ssh_key::authorized_keys::AuthorizedKeys::new(&authorized_keys);
while let Some(r) = authorized_keys.next() {
let entry = r?;
if entry.public_key().key_data() == public_key.key_data() {
return Ok(());
while let Some(r) = authorized_keys.next() {
let entry = r?;
if entry.public_key().key_data() == public_key.key_data() {
return Ok(());
}
}
}
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => {
error!("unable to read authorized keys file at {:?}: {}", authorized_keys, e);
}
};
Err(anyhow!("Key provided by the client is not authorized to connect"))
}

View File

@ -26,9 +26,7 @@ use std::future::Future;
use std::mem::ManuallyDrop;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::os::fd::FromRawFd;
use std::os::unix::process::CommandExt;
use std::pin::Pin;
use std::process::Stdio;
use std::ptr::NonNull;
use std::str::FromStr;
use std::sync::Arc;
@ -40,7 +38,6 @@ use nix::unistd::Uid;
use quinn::{ReadExactError, RecvStream, SendStream};
use rustls::client::ServerCertVerifier;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::process::Command;
use tracing::Instrument;
use user_info::UserInfo;
use webpki::SubjectNameRef;
@ -319,14 +316,6 @@ async fn run_server() -> Result<()> {
Ok(())
}
fn is_broken_pipe<T>(r: &Result<T, std::io::Error>) -> bool {
if let Err(e) = r {
e.kind() == std::io::ErrorKind::BrokenPipe
} else {
false
}
}
fn transport_config() -> quinn::TransportConfig {
let mut transport = quinn::TransportConfig::default();
transport.stream_receive_window((64u32 * 1024 * 1024).into());
@ -545,7 +534,7 @@ impl ServerCertVerifier for InformedServerCertVerifier {
}
}
let cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?;
let _cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?;
let ip_addr_slot;
let subject_name = match server_name {
@ -785,8 +774,7 @@ async fn run_client(mut args: std::env::Args) -> Result<()> {
.as_ref()
.and_then(|s| s.split_once('@'))
.context("Expected an argument of the form USERNAME@HOST")?;
let (host_name, port) = host.split_once(':').unwrap_or((host, "8022"));
let port = port.parse::<u16>()?;
let (host_name, _port) = host.split_once(':').unwrap_or((host, "8022"));
let mut client_crypto = rustls::ClientConfig::builder()
.with_safe_defaults()
@ -935,7 +923,7 @@ async fn do_forward_to(conn: &quinn::Connection, spec: ForwardSpec) -> Result<()
socket.bind(spec.bind.into())?;
let list = socket.listen(1024)?;
loop {
let (mut local_stream, peer) = list.accept().await?;
let (mut local_stream, _peer) = list.accept().await?;
let (send, recv) = open_stream(
conn,
&Stream::Forward {
@ -1083,7 +1071,7 @@ async fn greet_conn(cfg: &'static ServerConfig, conn: quinn::Connecting) -> Resu
#[cfg(feature = "server")]
async fn authenticate_conn(
cfg: &'static ServerConfig,
_cfg: &'static ServerConfig,
conn: &quinn::Connection,
) -> Result<(UserInfo, Vec<(CString, CString)>)> {
info!("authenticating connection");
@ -1192,78 +1180,16 @@ async fn handle_conn(
}
async fn handle_stream_exec(
cfg: &ServerConfig,
mut send: SendStream,
mut recv: RecvStream,
user_info: &UserInfo,
_cfg: &ServerConfig,
_send: SendStream,
_recv: RecvStream,
_user_info: &UserInfo,
) -> Result<()> {
(|| todo!())();
let mut cmd = std::process::Command::new("");
cmd.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::piped());
#[cfg(target_family = "unix")]
cmd.process_group(0);
info!("Running {:?}", cmd);
let mut sh = Command::from(cmd).kill_on_drop(true).spawn()?;
let mut stdout = sh.stdout.take().unwrap();
let mut stderr = sh.stderr.take().unwrap();
let mut stdin = sh.stdin.take().unwrap();
let mut stdout_buf = Vec::with_capacity(4096);
let mut stderr_buf = Vec::with_capacity(4096);
let mut stdin_buf = Vec::with_capacity(4096);
let mut stdout_eof = false;
let mut stderr_eof = false;
loop {
tokio::select! {
r = sh.wait() => {
let code = r?;
send.finish().await?;
if !code.success() {
info!("Child exit: {}", code);
recv.stop(1u8.into())?;
return Ok(());
} else {
info!("Child exit");
recv.stop(0u8.into())?;
return Ok(());
}
}
r = stdout.read_buf(&mut stdout_buf), if !stdout_eof => {
if is_broken_pipe(&r) || r? == 0 {
stdout_eof = true;
info!("stdout eof");
} else {
send.write_all(&stdout_buf).await?;
info!("sent stdout: {:x?}", stdout_buf);
stdout_buf.clear();
}
},
r = stderr.read_buf(&mut stderr_buf), if !stderr_eof => {
if is_broken_pipe(&r) || r? == 0 {
stderr_eof = true;
info!("stderr eof");
} else {
send.write_all(&stderr_buf).await?;
stderr_buf.clear();
info!("sent stderr: {:x?}", stderr_buf);
}
},
r = recv.read_buf(&mut stdin_buf) => if r? > 0 {
stdin.write_all(&stdin_buf).await?;
stdin_buf.clear();
info!("recv stdin");
},
}
}
todo!()
}
async fn handle_stream_shell(
cfg: &ServerConfig,
_cfg: &ServerConfig,
mut send: SendStream,
mut recv: RecvStream,
user_info: &UserInfo,
@ -1636,7 +1562,7 @@ async fn handle_stream_shell(
}
async fn handle_stream_forward(
cfg: &ServerConfig,
_cfg: &ServerConfig,
send: SendStream,
recv: RecvStream,
addr: Ipv4Addr,

View File

@ -1,3 +1,5 @@
//! Forked from <https://github.com/gifnksm/etc-passwd>.
//!
//! Get user information stored in the password file `/etc/passwd`.
//!
//! This crate provides a safe wrapper for libc functions such as [`getpwnam_r(3)`] and [`getpwuid_r(3)`].