summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/credential/cargo-credential-wincred
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /src/tools/cargo/credential/cargo-credential-wincred
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/cargo/credential/cargo-credential-wincred')
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml14
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/src/main.rs122
2 files changed, 136 insertions, 0 deletions
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
new file mode 100644
index 000000000..cd168a8a3
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "cargo-credential-wincred"
+version = "0.2.0"
+edition = "2021"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-lang/cargo"
+description = "A Cargo credential process that stores tokens with Windows Credential Manager."
+
+[dependencies]
+cargo-credential.workspace = true
+
+[target.'cfg(windows)'.dependencies.windows-sys]
+features = ["Win32_Foundation", "Win32_Security_Credentials"]
+workspace = true
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs
new file mode 100644
index 000000000..4377172e8
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs
@@ -0,0 +1,122 @@
+//! Cargo registry windows credential process.
+
+#[cfg(windows)]
+mod win {
+ use cargo_credential::{Credential, Error};
+ use std::ffi::OsStr;
+ use std::os::windows::ffi::OsStrExt;
+
+ use windows_sys::core::PWSTR;
+ use windows_sys::Win32::Foundation::ERROR_NOT_FOUND;
+ use windows_sys::Win32::Foundation::FILETIME;
+ use windows_sys::Win32::Foundation::TRUE;
+ use windows_sys::Win32::Security::Credentials::CredDeleteW;
+ use windows_sys::Win32::Security::Credentials::CredReadW;
+ use windows_sys::Win32::Security::Credentials::CredWriteW;
+ use windows_sys::Win32::Security::Credentials::CREDENTIALW;
+ use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE;
+ use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC;
+
+ pub(crate) struct WindowsCredential;
+
+ /// Converts a string to a nul-terminated wide UTF-16 byte sequence.
+ fn wstr(s: &str) -> Vec<u16> {
+ let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect();
+ if wide.iter().any(|b| *b == 0) {
+ panic!("nul byte in wide string");
+ }
+ wide.push(0);
+ wide
+ }
+
+ fn target_name(registry_name: &str) -> Vec<u16> {
+ wstr(&format!("cargo-registry:{}", registry_name))
+ }
+
+ impl Credential for WindowsCredential {
+ fn name(&self) -> &'static str {
+ env!("CARGO_PKG_NAME")
+ }
+
+ fn get(&self, index_url: &str) -> Result<String, Error> {
+ let target_name = target_name(index_url);
+ let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _;
+ unsafe {
+ if CredReadW(
+ target_name.as_ptr(),
+ CRED_TYPE_GENERIC,
+ 0,
+ p_credential as *mut _ as *mut _,
+ ) != TRUE
+ {
+ return Err(format!(
+ "failed to fetch token: {}",
+ std::io::Error::last_os_error()
+ )
+ .into());
+ }
+ let bytes = std::slice::from_raw_parts(
+ (*p_credential).CredentialBlob,
+ (*p_credential).CredentialBlobSize as usize,
+ );
+ String::from_utf8(bytes.to_vec())
+ .map_err(|_| "failed to convert token to UTF8".into())
+ }
+ }
+
+ fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
+ let token = token.as_bytes();
+ let target_name = target_name(index_url);
+ let comment = match name {
+ Some(name) => wstr(&format!("Cargo registry token for {}", name)),
+ None => wstr("Cargo registry token"),
+ };
+ let mut credential = CREDENTIALW {
+ Flags: 0,
+ Type: CRED_TYPE_GENERIC,
+ TargetName: target_name.as_ptr() as PWSTR,
+ Comment: comment.as_ptr() as PWSTR,
+ LastWritten: FILETIME {
+ dwLowDateTime: 0,
+ dwHighDateTime: 0,
+ },
+ CredentialBlobSize: token.len() as u32,
+ CredentialBlob: token.as_ptr() as *mut u8,
+ Persist: CRED_PERSIST_LOCAL_MACHINE,
+ AttributeCount: 0,
+ Attributes: std::ptr::null_mut(),
+ TargetAlias: std::ptr::null_mut(),
+ UserName: std::ptr::null_mut(),
+ };
+ let result = unsafe { CredWriteW(&mut credential, 0) };
+ if result != TRUE {
+ let err = std::io::Error::last_os_error();
+ return Err(format!("failed to store token: {}", err).into());
+ }
+ Ok(())
+ }
+
+ fn erase(&self, index_url: &str) -> Result<(), Error> {
+ let target_name = target_name(index_url);
+ let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) };
+ if result != TRUE {
+ let err = std::io::Error::last_os_error();
+ if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) {
+ eprintln!("not currently logged in to `{}`", index_url);
+ return Ok(());
+ }
+ return Err(format!("failed to remove token: {}", err).into());
+ }
+ Ok(())
+ }
+ }
+}
+
+#[cfg(not(windows))]
+use cargo_credential::UnsupportedCredential as WindowsCredential;
+#[cfg(windows)]
+use win::WindowsCredential;
+
+fn main() {
+ cargo_credential::main(WindowsCredential);
+}