Guest User

Untitled

a guest
Jul 14th, 2017
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 21.40 KB | None | 0 0
  1. use bytes::{Buf, BufMut, IntoBuf};
  2. use futures::{Async, Future, Poll};
  3. use hyper::Uri;
  4. use hyper::client::{HttpConnector, Service};
  5. use hyper_tls::{HttpsConnector, MaybeHttpsStream};
  6. use native_tls::TlsConnector;
  7. use tokio_core::reactor;
  8. use tokio_io::{AsyncRead, AsyncWrite};
  9. use tokio_tls::{TlsConnectorExt, TlsStream};
  10. use winauth::windows::NtlmSspiBuilder;
  11. use winauth::NextBytes;
  12. use base64;
  13.  
  14. use std::error::Error;
  15. use std::io::{self, Cursor, Read, Write};
  16. use std::sync::Arc;
  17. use std::str;
  18.  
  19. /// The header and prefix value in the NTLM challenge header sent
  20. /// back by an NTLM proxy.
  21. /// The whitespace at the end is significant. Do not remove it.
  22. const NTLM_CHLG_HDR_PREFIX: &'static str = "Proxy-Authenticate: NTLM ";
  23.  
  24. /// A future that resolves to a connection.
  25. pub type Connecting = Box<Future<Item=ConnectionType, Error=io::Error>>;
  26.  
  27. /// A `Connector` capable of authenticating to NTLM proxies on Windows.
  28. pub struct NtlmProxyConnector {
  29.    https: HttpsConnector<HttpConnector>,
  30.    proxy_addr: Uri,
  31.    tls: Arc<TlsConnector>,
  32. }
  33.  
  34. type HttpStream = <HttpConnector as Service>::Response;
  35. type HttpsStream = MaybeHttpsStream<HttpStream>;
  36.  
  37. pub enum ConnectionType {
  38.    Normal(HttpsStream),
  39.    Proxied(TlsStream<MaybeHttpsStream<HttpStream>>),
  40. }
  41.  
  42. /// Handles the process of establishing a tunnel through an NTLM proxy.
  43. ///
  44. /// Note that the `conn` and `state` fields are stored in `Option` so that we can
  45. /// use `Option::take()` to move ownership of their contents later. In each of the
  46. /// `Tunnel`'s methods that return `StateTransition`, `state` will be `None`, so
  47. /// don't bother trying to read it.
  48. struct Tunnel<T> {
  49.     buf: Cursor<Vec<u8>>,
  50.     conn: Option<T>, // Stored in an option so we can .take() ownership of it later.
  51.     state: TunnelState,
  52.     ntlm_ctx: Option<Box<NextBytes>>,
  53.     host: String,
  54.     port: u16,
  55. }
  56.  
  57. #[derive(Clone)]
  58. struct NtlmChallenge(pub String);
  59.  
  60. /// Represents the states of the tunnel establishing process.
  61. ///
  62. /// We expect the states to transition from `WritingInitial` to `ReadingChallenge` to `WritingResponse`.
  63. /// The `Failure` state should be jumped to as soon as an error occurs.
  64. ///
  65. /// In order to complete the NTLM authentication process, the SSPI context has to be passed between the
  66. /// `ReadingChallenge` and `WritingResponse` states. Neglecting to pass the same context will cause auth to fail.
  67. #[derive(Clone)]
  68. enum TunnelState {
  69.     WriteInitial,
  70.     ReadChallenge,
  71.     WriteResponse(NtlmChallenge),
  72.     ReadConfirm,
  73.     Done,
  74.     Failure
  75. }
  76.  
  77. /// Represents the outcomes of attempting to do a state transition from one `TunnelState` to the next.
  78. ///
  79. /// Each `TunnelState` may perform some asynchronous operations that may not have completed by the
  80. /// time the transition function (defined as a method of the `Tunnel` type) executes. In such a
  81. /// scenario, we would like for the `Tunnel` future's `poll()` method to be able to propagate the
  82. /// `Async::NotReady` status from the state transition function.
  83. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  84. enum StateTransition {
  85.     Continue,
  86.     NotReady,
  87.     Error,
  88. }
  89.  
  90. impl NtlmProxyConnector {
  91.     /// Constructs a new `NtlmProxyConnector` capable of handling TLS through a proxy given its address.
  92.     pub fn new(tls: TlsConnector, proxy_uri: Uri, handle: &reactor::Handle) -> NtlmProxyConnector {
  93.         let mut http = HttpConnector::new(4, handle);
  94.         http.enforce_http(false);
  95.         let https = HttpsConnector::from((http, tls.clone()));
  96.         let tls = Arc::new(tls);
  97.  
  98.         println!("Constructed NtlmProxyConnector");
  99.         NtlmProxyConnector {
  100.             https: https,
  101.             proxy_addr: proxy_uri,
  102.             tls: tls,
  103.         }
  104.     }
  105. }
  106.  
  107. impl Service for NtlmProxyConnector {
  108.     type Request = Uri;
  109.     type Response = ConnectionType;
  110.     type Error = io::Error;
  111.     type Future = Connecting;
  112.  
  113.     fn call(&self, uri: Uri) -> Self::Future {
  114.         match uri.scheme() {
  115.             Some("https") => {
  116.                 println!("Got an HTTPS request");
  117.                 let host = uri.host().unwrap().to_owned();
  118.                 let port = uri.port().unwrap_or(443);
  119.                 let tls = self.tls.clone();
  120.                 let host_copy = host.to_owned();
  121.                 Box::new(self.https.call(self.proxy_addr.clone()).and_then(move |conn| {
  122.                     Tunnel::new(conn, host_copy, port)
  123.                         .and_then(move |tunneled| {
  124.                             tls.connect_async(&host, tunneled)
  125.                                 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
  126.                             })
  127.                             .map(|io| ConnectionType::Proxied(io))
  128.                 }))
  129. //                Box::new(self.https
  130. //                    .call(self.proxy_addr.clone())
  131. //                    .and_then(move |conn| Tunnel::new(conn, host_copy, port))
  132. //                    .and_then(move |tunn| tls.connect_async(host.as_str(), tunn)
  133. //                              .map_err(|_| io::Error::new(io::ErrorKind::ConnectionAborted,
  134. //                                                          "tunnel failed to connect")))
  135. //                    .map(ConnectionType::Proxied))
  136.             },
  137.             _ => {
  138.                 println!("Got an HTTP request");
  139.                 Box::new(self.https
  140.                     .call(self.proxy_addr.clone())
  141.                     .map(ConnectionType::Normal))
  142.             },
  143.  
  144.         }
  145.     }
  146. }
  147.  
  148. impl<T> Tunnel<T>
  149.     where T: AsyncRead + AsyncWrite
  150. {
  151.     /// Constructs a new `Tunnel` that will attempt to tunnel through a specified proxy.
  152.     pub fn new(conn: T, host: String, port: u16) -> Self {
  153.         let empty_buf = String::new().into_bytes();
  154.         Tunnel {
  155.             buf: empty_buf.into_buf(),
  156.             conn: Some(conn),
  157.             state: TunnelState::WriteInitial,
  158.             ntlm_ctx: None,
  159.             host: host,
  160.             port: port,
  161.         }
  162.     }
  163.  
  164.     fn begin_ntlm_handshake(&mut self) -> StateTransition {
  165.         println!("In begin_ntlm_handshake");
  166.         self.ntlm_ctx = Some(Box::new(NtlmSspiBuilder::new().build().unwrap()));
  167.         self.state = TunnelState::ReadChallenge;
  168.         StateTransition::Continue
  169. //        let mut sspi = match NtlmSspiBuilder::new().build() {
  170. //            Ok(ntlm_ctx) => ntlm_ctx,
  171. //            Err(err) => {
  172. //                self.state = Some(TunnelState::Failure(
  173. //                    io::Error::new(io::ErrorKind::Other, err.description().to_owned())));
  174. //                return StateTransition::Error;
  175. //            }
  176. //        };
  177. //        println!("In begin_ntlm_handshake, created NTLM context");
  178. //        let negotiate_bytes = match sspi.next_bytes(None) {
  179. //            Ok(Some(bytes)) => bytes,
  180. //            Ok(None) => {
  181. //                self.state = Some(TunnelState::Failure(
  182. //                    io::Error::new(io::ErrorKind::Other, String::from("failed to read NTLM initial bytes"))));
  183. //                return StateTransition::Error;
  184. //            },
  185. //            Err(error) => {
  186. //                self.state = Some(TunnelState::Failure(
  187. //                    io::Error::new(io::ErrorKind::Other, error.description().to_owned())));
  188. //                return StateTransition::Error;
  189. //            }
  190. //        };
  191. //        println!("Got initial NTLM handshake bytes");
  192. //        let negotiation = base64::encode(&*negotiate_bytes);
  193. //        let request_content = format!(
  194. //            "CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\nProxy-Authorization: NTLM {neg}\r\n\r\n",
  195. //            host=self.host,
  196. //            port=self.port,
  197. //            neg=negotiation);
  198. //        self.buf = request_content.into_bytes().into_buf();
  199. //        let bytes_written = match self.conn.as_mut().unwrap().write_buf(&mut self.buf) {
  200. //            Ok(Async::Ready(written)) => written,
  201. //            Ok(Async::NotReady) => {
  202. //                self.state = Some(TunnelState::WriteInitial);
  203. //                return StateTransition::NotReady;
  204. //            },
  205. //            Err(error) => {
  206. //                self.state = Some(TunnelState::Failure(
  207. //                    io::Error::new(io::ErrorKind::Other,
  208. //                                   error.description().to_owned())));
  209. //                return StateTransition::Error;
  210. //            }
  211. //        };
  212. //        if !self.buf.has_remaining_mut() && bytes_written > 0 {
  213. //            println!("Successfully wrote first request");
  214. //            self.state = Some(TunnelState::ReadChallenge(Box::new(sspi)));
  215. //            println!("Updated state");
  216. //            self.buf.get_mut().truncate(0);
  217. //            StateTransition::Continue
  218. //        } else {
  219. //            println!("Failed to write first request");
  220. //            self.state = Some(TunnelState::Failure(
  221. //                io::Error::new(io::ErrorKind::UnexpectedEof, String::from("unexpected EOF while tunneling"))));
  222. //            StateTransition::Error
  223. //        }
  224.     }
  225.  
  226.     fn read_challenge(&mut self) -> StateTransition {
  227.         println!("In read_challenge");
  228.         let challenge = NtlmChallenge(String::from("fakechallenge"));
  229.         //self.state = TunnelState::WriteResponse(challenge, ntlm_ctx);
  230.         StateTransition::NotReady
  231. //        println!("Attempting to read challenge");
  232. //        let bytes_read = match self.conn.as_mut().unwrap().read_buf(&mut self.buf.get_mut()) {
  233. //            Ok(Async::Ready(read)) => read,
  234. //            Ok(Async::NotReady) => {
  235. //                println!("Not ready to read bytes");
  236. //                self.state = Some(TunnelState::ReadChallenge(ntlm_ctx));
  237. //                return StateTransition::NotReady;
  238. //            },
  239. //            Err(error) => {
  240. //                self.state = Some(TunnelState::Failure(
  241. //                    io::Error::new(io::ErrorKind::Other,
  242. //                                   error.description().to_owned())));
  243. //                return StateTransition::Error;
  244. //            }
  245. //        };
  246. //        let read = &self.buf.get_ref()[..].to_owned();
  247. //        if bytes_read == 0 {
  248. //            self.state = Some(TunnelState::Failure(
  249. //                io::Error::new(io::ErrorKind::UnexpectedEof, String::from("unexpected EOF while tunneling"))));
  250. //            return StateTransition::Error;
  251. //        }
  252. //        if read.len() <= 12 {
  253. //            self.state = Some(TunnelState::Failure(
  254. //                io::Error::new(io::ErrorKind::InvalidData, String::from("did not read enough bytes"))));
  255. //            return StateTransition::Error;
  256. //        }
  257. //        // Handle the case where we are talking to an NTLM proxy and have completely read its
  258. //        // response. If we haven't read the whole response, the tunnel should remain in its current
  259. //        // state so that we come back to this method and read more bytes.
  260. //        //
  261. //        // If we find that the response contains a regular status 200, then we don't have to do
  262. //        // any more work and can move straight to the final `Done` state.
  263. //        let end = b"\r\n\r\n";
  264. //        if read.starts_with(b"HTTP/1.0 407") || read.starts_with(b"HTTP/1.1 407") {
  265. //            if read.ends_with(end) {
  266. //                println!("Read challenge response");
  267. //                let res = String::from_utf8_lossy(read);
  268. //                let parts: Vec<&str> = res.split(NTLM_CHLG_HDR_PREFIX).collect();
  269. //                if parts.len() < 2 {
  270. //                    self.state = Some(TunnelState::Failure(
  271. //                        io::Error::new(io::ErrorKind::Other, String::from("Proxy-Authenticate header not found"))));
  272. //                    return StateTransition::Error;
  273. //                }
  274. //                let parts: Vec<&str> = parts[1].split("\r\n").collect();
  275. //                self.state = Some(TunnelState::WriteResponse(NtlmChallenge(parts[0].trim().to_owned()), ntlm_ctx));
  276. //                println!("Successfully parsed NTLM challenge");
  277. //            }
  278. //            // Else (do nothing to) stay in the current state to read more.
  279. //            return StateTransition::Continue;
  280. //        } else if read.starts_with(b"HTTP/1.0 200") || read.starts_with(b"HTTP/1.1 200") {
  281. //            if read.ends_with(end) {
  282. //                println!("Looks like we don't need to do NTLM handshake");
  283. //                self.state = Some(TunnelState::Done);
  284. //            }
  285. //            // Else (do nothing to) stay in the current state to read more.
  286. //            return StateTransition::Continue;
  287. //        } else {
  288. //            println!("Error reading challenge response");
  289. //            self.state = Some(TunnelState::Failure(
  290. //                io::Error::new(io::ErrorKind::ConnectionRefused, String::from("unsuccessful tunnel setup"))));
  291. //            return StateTransition::Error;
  292. //        }
  293.     }
  294.  
  295.     fn respond_to_challenge(&mut self, ch: NtlmChallenge) -> StateTransition {
  296.         println!("In respond_to_challenge");
  297.         self.state = TunnelState::ReadConfirm;
  298.         StateTransition::Continue
  299. //        let challenge = ch.0;
  300. //        let decoded = match base64::decode(challenge.as_str()) {
  301. //            Ok(bytes) => bytes,
  302. //            Err(_) => {
  303. //                self.state = Some(TunnelState::Failure(
  304. //                    io::Error::new(io::ErrorKind::Other, format!("got invalid challenge: {}", challenge))));
  305. //                return StateTransition::Error;
  306. //            }
  307. //        };
  308. //        println!("Decoded challenge");
  309. //        let auth_response = match ntlm_ctx.as_mut().next_bytes(Some(&decoded)) {
  310. //            Ok(Some(auth)) => auth,
  311. //            Ok(None) => {
  312. //                self.state = Some(TunnelState::Failure(
  313. //                    io::Error::new(io::ErrorKind::Other, String::from("failed to process response to challenge"))));
  314. //                return StateTransition::Error;
  315. //            },
  316. //            Err(err) => {
  317. //                self.state = Some(TunnelState::Failure(
  318. //                    io::Error::new(io::ErrorKind::Other, err.description().to_owned())));
  319. //                return StateTransition::Error;
  320. //            }
  321. //        };
  322. //        println!("Produced response to challenge");
  323. //        let challenge_response = base64::encode(&*auth_response);
  324. //        let response = format!(
  325. //            "CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\nProxy-Authorization: NTLM {res}\r\n\r\n",
  326. //            host=self.host,
  327. //            port=self.port,
  328. //            res=challenge_response);
  329. //        self.buf = response.into_bytes().into_buf();
  330. //        let bytes_written = match self.conn.as_mut().unwrap().write_buf(&mut self.buf) {
  331. //            Ok(Async::Ready(written)) => written,
  332. //            Ok(Async::NotReady) => {
  333. //                self.state = Some(TunnelState::WriteResponse(NtlmChallenge(challenge), ntlm_ctx));
  334. //                return StateTransition::NotReady;
  335. //            },
  336. //            Err(error) => {
  337. //                self.state = Some(TunnelState::Failure(
  338. //                    io::Error::new(io::ErrorKind::Other,
  339. //                                   error.description().to_owned())));
  340. //                return StateTransition::Error;
  341. //            }
  342. //        };
  343. //        if !self.buf.has_remaining_mut() && bytes_written > 0 {
  344. //            println!("Successfully wrote challenge response");
  345. //            self.state = Some(TunnelState::ReadConfirm);
  346. //            self.buf.get_mut().truncate(0);
  347. //            StateTransition::Continue
  348. //        } else {
  349. //            println!("Failed to write challenge response");
  350. //            self.state = Some(TunnelState::Failure(
  351. //                io::Error::new(io::ErrorKind::UnexpectedEof, String::from("unexpected EOF while tunneling"))));
  352. //            StateTransition::Error
  353. //        }
  354.     }
  355.  
  356.     fn verify_handshake_completed(&mut self) -> StateTransition {
  357.         println!("In verify_handshake_completed");
  358.         self.state = TunnelState::Done;
  359.         StateTransition::Continue
  360. //        let bytes_read = match self.conn.as_mut().unwrap().read_buf(&mut self.buf.get_mut()) {
  361. //            Ok(Async::Ready(read)) => read,
  362. //            Ok(Async::NotReady) => {
  363. //                self.state = Some(TunnelState::ReadConfirm);
  364. //                return StateTransition::NotReady;
  365. //            },
  366. //            Err(error) => {
  367. //                self.state = Some(TunnelState::Failure(
  368. //                    io::Error::new(io::ErrorKind::Other,
  369. //                                   error.description().to_owned())));
  370. //                return StateTransition::Error;
  371. //            }
  372. //        };
  373. //        let read = &self.buf.get_ref()[..].to_owned();
  374. //        if bytes_read == 0 {
  375. //            self.state = Some(TunnelState::Failure(
  376. //                io::Error::new(io::ErrorKind::UnexpectedEof, String::from("unexpected EOF while tunneling"))));
  377. //            return StateTransition::Error;
  378. //        }
  379. //        if read.len() <= 12 {
  380. //            self.state = Some(TunnelState::Failure(
  381. //                io::Error::new(io::ErrorKind::InvalidData, String::from("did not read enough bytes"))));
  382. //            return StateTransition::Error;
  383. //        }
  384. //        if read.starts_with(b"HTTP/1.0 200") || read.starts_with(b"HTTP/1.1 200") {
  385. //            println!("Verified that the handshake completed");
  386. //            self.state = Some(TunnelState::Done);
  387. //            StateTransition::Continue
  388. //        } else {
  389. //            println!("Handshake verification failed");
  390. //            self.state = Some(TunnelState::Failure(
  391. //                io::Error::new(io::ErrorKind::ConnectionRefused, String::from("proxy did not accept challenge response"))));
  392. //            StateTransition::Error
  393. //        }
  394.     }
  395. }
  396.  
  397. impl<T> Future for Tunnel<T>
  398.     where T: AsyncRead + AsyncWrite
  399. {
  400.     type Item = T;
  401.     type Error = io::Error;
  402.  
  403.     /// Handles state transitions for authenticating to an NTLM proxy.
  404.     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
  405.         println!("Called poll()");
  406.         loop {
  407.             println!("At top of tunnel.poll");
  408.             // Note about state transitions:
  409.             // Be careful with how the tunnel is used after calling self.state.take().
  410.             // At this point the tunnel's state will be None, so trying to read the state in
  411.             // any of the state transition functions below probably won't work how you'd expect.
  412.             let current_state = self.state.clone();
  413.             let state_trans_status = match current_state {
  414.                 TunnelState::WriteInitial                  => self.begin_ntlm_handshake(),
  415.                 TunnelState::ReadChallenge       => self.read_challenge(),
  416.                 TunnelState::WriteResponse(chal) => self.respond_to_challenge(chal),
  417.                 TunnelState::ReadConfirm                   => self.verify_handshake_completed(),
  418.                 TunnelState::Done                          => { return Ok(Async::Ready(self.conn.take().unwrap())); },
  419.                 TunnelState::Failure                => { return Err(io::Error::new(io::ErrorKind::Other, String::from("didn't work, sorry"))); },
  420.             };
  421.             // If the transition status is `Error`, then the tunnel will have entered `TunnelState::Failure`,
  422.             // so we don't need to handle that here (it gets handled above).
  423.             // Likewise, if the status is `Continue`, we can just let the loop go ahead and run again.
  424.             if state_trans_status == StateTransition::NotReady {
  425.                 println!("Tunnel is not ready");
  426.                 return Ok(Async::NotReady);
  427.             }
  428.         }
  429.     }
  430. }
  431.  
  432. impl Read for ConnectionType {
  433.     #[inline]
  434.     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  435.         match *self {
  436.             ConnectionType::Normal(ref mut stream)  => stream.read(buf),
  437.             ConnectionType::Proxied(ref mut stream) => stream.read(buf),
  438.         }
  439.     }
  440. }
  441.  
  442. impl Write for ConnectionType {
  443.     #[inline]
  444.     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  445.         match *self {
  446.             ConnectionType::Normal(ref mut stream)  => stream.write(buf),
  447.             ConnectionType::Proxied(ref mut stream) => stream.write(buf),
  448.         }
  449.     }
  450.  
  451.     #[inline]
  452.     fn flush(&mut self) -> io::Result<()> {
  453.         match *self {
  454.             ConnectionType::Normal(ref mut stream)  => stream.flush(),
  455.             ConnectionType::Proxied(ref mut stream) => stream.flush(),
  456.         }
  457.     }
  458. }
  459.  
  460. impl AsyncRead for ConnectionType {
  461.     unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
  462.         match *self {
  463.             ConnectionType::Normal(ref stream)  => stream.prepare_uninitialized_buffer(buf),
  464.             ConnectionType::Proxied(ref stream) => stream.prepare_uninitialized_buffer(buf),
  465.         }
  466.     }
  467.  
  468.     fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
  469.         match *self {
  470.             ConnectionType::Normal(ref mut stream)  => stream.read_buf(buf),
  471.             ConnectionType::Proxied(ref mut stream) => stream.read_buf(buf),
  472.         }
  473.     }
  474. }
  475.  
  476. impl AsyncWrite for ConnectionType {
  477.     fn shutdown(&mut self) -> Poll<(), io::Error> {
  478.         match *self {
  479.             ConnectionType::Normal(ref mut stream)  => stream.shutdown(),
  480.             ConnectionType::Proxied(ref mut stream) => stream.shutdown(),
  481.         }
  482.     }
  483.  
  484.     fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
  485.         match *self {
  486.             ConnectionType::Normal(ref mut stream)  => stream.write_buf(buf),
  487.             ConnectionType::Proxied(ref mut stream) => stream.write_buf(buf),
  488.         }
  489.     }
  490. }
Add Comment
Please, Sign In to add comment