Skip to content

Commit d8f1211

Browse files
fix(dpapi): panic in dpapi due to missing io driver (#586)
During manual initialization of the tokio runtime, the I/O driver wasn't enabled, leading to a panic later when performing RPC. Also: * Tweaks address parsing to avoid breaking on IPv6 addresses. Although using DPAPI with only an IP address is unlikely to work, at least now a better error will be returned, instead of an "invalid port" error. * Tweaks DPAPI response parsing to read the result code even if the response has an unexpected lenght.
1 parent 2057f70 commit d8f1211

File tree

4 files changed

+31
-14
lines changed

4 files changed

+31
-14
lines changed

crates/dpapi-transport/src/connect_options.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::future::Future;
2+
use std::net::IpAddr;
23
use std::pin::Pin;
34

45
use thiserror::Error;
5-
use url::Url;
6+
use url::{Host, Url};
67
use uuid::Uuid;
78

89
/// Type that represents a function for obtaining the session token.
@@ -70,6 +71,13 @@ impl ConnectOptions {
7071
pub fn new(destination: &str, proxy_options: Option<ProxyOptions>) -> Result<Self> {
7172
let mut destination = Url::parse(&if destination.contains("://") {
7273
destination.to_owned()
74+
} else if let Ok(ip_attempt) = destination.parse::<IpAddr>() {
75+
// Ensure IP address format is valid for URLs
76+
let ip_str_valid = match ip_attempt {
77+
IpAddr::V4(ipv4_addr) => Host::Ipv4::<String>(ipv4_addr).to_string(),
78+
IpAddr::V6(ipv6_addr) => Host::Ipv6::<String>(ipv6_addr).to_string(),
79+
};
80+
format!("tcp://{ip_str_valid}")
7381
} else {
7482
format!("tcp://{destination}")
7583
})?;

crates/dpapi/src/gkdi.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,21 @@ pub enum GkdiError {
3939

4040
/// Checks the RPC GetKey Response status (`hresult`) and tries to parse the data into [GroupKeyEnvelope].
4141
pub fn unpack_response(data: &[u8]) -> Result<GroupKeyEnvelope> {
42-
if data.len() < 4 /* key_length */ + 4 /* padding */ + 8 /* referent id */ + 8 /* pointer size */ + 4
43-
/* status */
44-
{
45-
Err(GkdiError::BadResponse("response data length is too small"))?;
46-
}
47-
48-
let (key_buf, mut hresult_buf) = data.split_at(data.len() - size_of::<u32>());
42+
let (key_buf, mut hresult_buf) = data
43+
.split_at_checked(data.len() - size_of::<u32>())
44+
.ok_or(GkdiError::BadResponse("response data length is too small"))?;
4945

5046
let hresult = hresult_buf.read_u32::<LittleEndian>()?;
5147
if hresult != 0 {
5248
Err(GkdiError::BadHresult(hresult))?;
5349
}
5450

51+
if data.len() < 4 /* key_length */ + 4 /* padding */ + 8 /* referent id */ + 8 /* pointer size */ + 4
52+
/* status */
53+
{
54+
Err(GkdiError::BadResponse("response data length is too small"))?;
55+
}
56+
5557
let mut src = ReadCursor::new(key_buf);
5658

5759
let _key_length = src.read_u32();

ffi/src/dpapi/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub unsafe extern "system" fn DpapiProtectSecret(
180180
};
181181
let mut network_client = network_client::SyncNetworkClient;
182182

183-
let runtime = try_execute!(Builder::new_current_thread().build(), NTE_INTERNAL_ERROR);
183+
let runtime = try_execute!(Builder::new_current_thread().enable_all().build(), NTE_INTERNAL_ERROR);
184184
let blob_data = try_execute!(
185185
runtime.block_on(n_crypt_protect_secret::<NativeTransport>(
186186
CryptProtectSecretArgs {
@@ -353,7 +353,7 @@ pub unsafe extern "system" fn DpapiUnprotectSecret(
353353
};
354354
let mut network_client = network_client::SyncNetworkClient;
355355

356-
let runtime = try_execute!(Builder::new_current_thread().build(), NTE_INTERNAL_ERROR);
356+
let runtime = try_execute!(Builder::new_current_thread().enable_all().build(), NTE_INTERNAL_ERROR);
357357
let secret_data = try_execute!(
358358
runtime.block_on(n_crypt_unprotect_secret::<NativeTransport>(
359359
CryptUnprotectSecretArgs {

tools/dpapi-cli-client/src/main.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ async fn run(data: Dpapi) -> Result<()> {
8282
stdin().bytes().collect::<Result<Vec<_>>>()?
8383
};
8484

85-
let secret = Box::pin(dpapi::n_crypt_unprotect_secret::<NativeTransport>(
85+
let result = Box::pin(dpapi::n_crypt_unprotect_secret::<NativeTransport>(
8686
CryptUnprotectSecretArgs {
8787
blob: &blob,
8888
server: &server,
@@ -94,10 +94,17 @@ async fn run(data: Dpapi) -> Result<()> {
9494
kerberos_config: None,
9595
},
9696
))
97-
.await
98-
.unwrap();
97+
.await;
9998

100-
stdout().write_all(secret.as_ref())?;
99+
match result {
100+
Ok(secret) => {
101+
stdout().write_all(secret.as_ref())?;
102+
}
103+
Err(error) => {
104+
println!("{:?}", error);
105+
}
106+
}
107+
101108
}
102109
}
103110

0 commit comments

Comments
 (0)