|
13 | 13 | // limitations under the License. |
14 | 14 | // |
15 | 15 | use std::cell::RefCell; |
| 16 | +use std::convert::TryInto; |
16 | 17 |
|
17 | 18 | use russh_cryptovec::CryptoVec; |
18 | 19 | use russh_keys::encoding::{Encoding, Reader}; |
19 | 20 | use russh_keys::key::parse_public_key; |
20 | 21 | use tokio::sync::mpsc::unbounded_channel; |
21 | 22 | use log::{debug, error, info, trace, warn}; |
22 | 23 |
|
23 | | -use crate::client::{Handler, Msg, Reply, Session}; |
| 24 | +use crate::client::{Handler, Msg, Reply, Session, Prompt}; |
24 | 25 | use crate::key::PubKey; |
25 | 26 | use crate::negotiation::{Named, Select}; |
26 | 27 | use crate::parsing::{ChannelOpenConfirmation, ChannelType, OpenChannelMessage}; |
@@ -230,13 +231,51 @@ impl Session { |
230 | 231 | if no_more_methods { |
231 | 232 | return Err(crate::Error::NoAuthMethod.into()); |
232 | 233 | } |
233 | | - } else if buf.first() == Some(&msg::USERAUTH_PK_OK) { |
| 234 | + |
| 235 | + } else if buf.first() == Some(&msg::USERAUTH_INFO_REQUEST) { |
| 236 | + let mut r = buf.reader(1); |
| 237 | + |
| 238 | + // read fields |
| 239 | + let name = String::from_utf8_lossy(r.read_string().map_err(crate::Error::from)?).to_string(); |
| 240 | + let instructions = String::from_utf8_lossy(r.read_string().map_err(crate::Error::from)?).to_string(); |
| 241 | + let _lang = r.read_string().map_err(crate::Error::from)?; |
| 242 | + let n_prompts = r.read_u32().map_err(crate::Error::from)?; |
| 243 | + |
| 244 | + // read prompts |
| 245 | + let mut prompts = Vec::with_capacity(n_prompts.try_into().unwrap_or(0)); |
| 246 | + for _i in 0..n_prompts { |
| 247 | + let prompt = String::from_utf8_lossy(r.read_string().map_err(crate::Error::from)?); |
| 248 | + let echo = r.read_byte().map_err(crate::Error::from)? != 0; |
| 249 | + prompts.push(Prompt{prompt: prompt.to_string(), echo}); |
| 250 | + } |
| 251 | + |
| 252 | + // send challenges to call handler |
| 253 | + self.sender |
| 254 | + .send(Reply::AuthInfoRequest { name, instructions, prompts }) |
| 255 | + .map_err(|_| crate::Error::SendError)?; |
| 256 | + |
| 257 | + // wait for response from handler |
| 258 | + let responses = loop { |
| 259 | + match self.receiver.recv().await { |
| 260 | + Some(Msg::AuthInfoResponse{ responses }) => break responses, |
| 261 | + _ => {} |
| 262 | + } |
| 263 | + }; |
| 264 | + // write responses |
| 265 | + enc.client_send_auth_response(&responses)?; |
| 266 | + |
| 267 | + return Ok((client, self)); |
| 268 | + } else if buf.first() == Some(&msg::USERAUTH_INFO_REQUEST_OR_USERAUTH_PK_OK) { |
234 | 269 | debug!("userauth_pk_ok"); |
235 | 270 | if let Some(auth::CurrentRequest::PublicKey { |
236 | 271 | ref mut sent_pk_ok, .. |
237 | 272 | }) = auth_request.current |
238 | 273 | { |
239 | 274 | *sent_pk_ok = true; |
| 275 | + } else if let Some(auth::CurrentRequest::KeyboardInteractive { ref submethods }) = auth_request.current { |
| 276 | + |
| 277 | + } else { |
| 278 | + unreachable!() |
240 | 279 | } |
241 | 280 |
|
242 | 281 | match self.common.auth_method.take() { |
@@ -766,6 +805,15 @@ impl Encrypted { |
766 | 805 | key.push_to(&mut self.write); |
767 | 806 | true |
768 | 807 | } |
| 808 | + auth::Method::KeyboardInteractive{ ref submethods } => { |
| 809 | + debug!("KEYBOARD INTERACTIVE"); |
| 810 | + self.write.extend_ssh_string(user.as_bytes()); |
| 811 | + self.write.extend_ssh_string(b"ssh-connection"); |
| 812 | + self.write.extend_ssh_string(b"keyboard-interactive"); |
| 813 | + self.write.extend_ssh_string(b""); // lang tag is deprecated. Should be empty |
| 814 | + self.write.extend_ssh_string(submethods.as_bytes()); |
| 815 | + true |
| 816 | + } |
769 | 817 | } |
770 | 818 | }) |
771 | 819 | } |
@@ -810,4 +858,19 @@ impl Encrypted { |
810 | 858 | } |
811 | 859 | Ok(()) |
812 | 860 | } |
| 861 | + |
| 862 | + //TODO |
| 863 | + fn client_send_auth_response( |
| 864 | + &mut self, |
| 865 | + responses: &[String] |
| 866 | + ) -> Result<(), crate::Error> { |
| 867 | + push_packet!(self.write, { |
| 868 | + self.write.push(msg::USERAUTH_INFO_RESPONSE); |
| 869 | + self.write.push(responses.len().try_into().unwrap_or(0)); // number of responses |
| 870 | + for r in responses { |
| 871 | + self.write.extend_ssh_string(r.as_bytes()); // write the reponses |
| 872 | + } |
| 873 | + }); |
| 874 | + Ok(()) |
| 875 | + } |
813 | 876 | } |
0 commit comments