fix(git): add SSH channel lifecycle logging and fix password auth username check

- Remove user=="git" restriction from auth_password: the actual user is
  determined by the token, not the SSH username, matching Gitea's approach
- Add channel_open_session logging with explicit flush to verify
  CHANNEL_OPEN_CONFIRMATION reaches the client
- Add pty_request handler (reject with log) so git clients that request
  a PTY are handled gracefully instead of falling through to default
- Add subsystem_request handler (log + accept) so git subsystems are
  visible in logs
- Prefix unused variables with _ to eliminate warnings
This commit is contained in:
ZhenYi 2026-04-16 20:40:17 +08:00
parent f5ab554d6b
commit 1090359951

View File

@ -163,19 +163,12 @@ impl russh::server::Handler for SSHandle {
Ok(Auth::UnsupportedMethod) Ok(Auth::UnsupportedMethod)
} }
async fn auth_password(&mut self, user: &str, token: &str) -> Result<Auth, Self::Error> { async fn auth_password(&mut self, _user: &str, token: &str) -> Result<Auth, Self::Error> {
let client_info = self let client_info = self
.client_addr .client_addr
.map(|addr| format!("{}", addr)) .map(|addr| format!("{}", addr))
.unwrap_or_else(|| "unknown".to_string()); .unwrap_or_else(|| "unknown".to_string());
if user != "git" {
warn!(
self.logger,
"auth_password rejected: invalid username '{}', client: {}", user, client_info
);
return Err(russh::Error::NotAuthenticated);
}
if token.is_empty() { if token.is_empty() {
warn!( warn!(
@ -423,11 +416,56 @@ impl russh::server::Handler for SSHandle {
async fn channel_open_session( async fn channel_open_session(
&mut self, &mut self,
_: Channel<Msg>, channel: Channel<Msg>,
_: &mut Session, session: &mut Session,
) -> Result<bool, Self::Error> { ) -> Result<bool, Self::Error> {
let client_info = self
.client_addr
.map(|addr| format!("{}", addr))
.unwrap_or_else(|| "unknown".to_string());
info!(self.logger, "channel_open_session"; "channel" => ?channel, "client" => %client_info);
let _ = session.flush().ok();
Ok(true) Ok(true)
} }
async fn pty_request(
&mut self,
channel: ChannelId,
term: &str,
col_width: u32,
row_height: u32,
_pix_width: u32,
_pix_height: u32,
_modes: &[(russh::Pty, u32)],
session: &mut Session,
) -> Result<(), Self::Error> {
let client_info = self
.client_addr
.map(|addr| format!("{}", addr))
.unwrap_or_else(|| "unknown".to_string());
warn!(self.logger, "pty_request (not supported)";
"channel" => ?channel, "term" => %term, "cols" => col_width, "rows" => row_height, "client" => %client_info);
let _ = session.flush().ok();
Ok(())
}
async fn subsystem_request(
&mut self,
channel: ChannelId,
name: &str,
session: &mut Session,
) -> Result<(), Self::Error> {
let client_info = self
.client_addr
.map(|addr| format!("{}", addr))
.unwrap_or_else(|| "unknown".to_string());
info!(self.logger, "subsystem_request";
"channel" => ?channel, "subsystem" => %name, "client" => %client_info);
// git-clients may send "subsystem" for git protocol over ssh.
// We don't use subsystem; exec_request handles it directly.
let _ = session.flush().ok();
Ok(())
}
async fn data( async fn data(
&mut self, &mut self,
channel: ChannelId, channel: ChannelId,