Fix SAS Service build errors
- Use raw FFI for named pipe operations instead of windows crate APIs - Add Win32_System_IO feature to Cargo.toml - Define pipe constants manually to avoid missing exports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,7 @@ windows = { version = "0.58", features = [
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_Pipes",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_IO",
|
||||
]}
|
||||
|
||||
# Windows service support
|
||||
|
||||
@@ -4,26 +4,13 @@
|
||||
//! The agent communicates with this service via named pipe IPC.
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::{Read, Write as IoWrite};
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use windows::core::{s, w, PCSTR};
|
||||
use windows::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
|
||||
use windows::Win32::Security::{
|
||||
InitializeSecurityDescriptor, SetSecurityDescriptorDacl, PSECURITY_DESCRIPTOR,
|
||||
SECURITY_ATTRIBUTES, SECURITY_DESCRIPTOR,
|
||||
};
|
||||
use windows::Win32::Storage::FileSystem::{
|
||||
FlushFileBuffers, ReadFile, WriteFile,
|
||||
};
|
||||
use windows::core::{s, w};
|
||||
use windows::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryW};
|
||||
use windows::Win32::System::Pipes::{
|
||||
ConnectNamedPipe, CreateNamedPipeW, DisconnectNamedPipe, PIPE_ACCESS_DUPLEX,
|
||||
PIPE_READMODE_MESSAGE, PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_WAIT,
|
||||
};
|
||||
use windows::Win32::System::SystemServices::SECURITY_DESCRIPTOR_REVISION;
|
||||
use windows_service::{
|
||||
define_windows_service,
|
||||
service::{
|
||||
@@ -42,6 +29,67 @@ const SERVICE_DESCRIPTION: &str = "Handles Secure Attention Sequence (Ctrl+Alt+D
|
||||
const PIPE_NAME: &str = r"\\.\pipe\guruconnect-sas";
|
||||
const INSTALL_DIR: &str = r"C:\Program Files\GuruConnect";
|
||||
|
||||
// Windows named pipe constants
|
||||
const PIPE_ACCESS_DUPLEX: u32 = 0x00000003;
|
||||
const PIPE_TYPE_MESSAGE: u32 = 0x00000004;
|
||||
const PIPE_READMODE_MESSAGE: u32 = 0x00000002;
|
||||
const PIPE_WAIT: u32 = 0x00000000;
|
||||
const PIPE_UNLIMITED_INSTANCES: u32 = 255;
|
||||
const INVALID_HANDLE_VALUE: isize = -1;
|
||||
const SECURITY_DESCRIPTOR_REVISION: u32 = 1;
|
||||
|
||||
// FFI declarations for named pipe operations
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
fn CreateNamedPipeW(
|
||||
lpName: *const u16,
|
||||
dwOpenMode: u32,
|
||||
dwPipeMode: u32,
|
||||
nMaxInstances: u32,
|
||||
nOutBufferSize: u32,
|
||||
nInBufferSize: u32,
|
||||
nDefaultTimeOut: u32,
|
||||
lpSecurityAttributes: *mut SECURITY_ATTRIBUTES,
|
||||
) -> isize;
|
||||
|
||||
fn ConnectNamedPipe(hNamedPipe: isize, lpOverlapped: *mut std::ffi::c_void) -> i32;
|
||||
fn DisconnectNamedPipe(hNamedPipe: isize) -> i32;
|
||||
fn CloseHandle(hObject: isize) -> i32;
|
||||
fn ReadFile(
|
||||
hFile: isize,
|
||||
lpBuffer: *mut u8,
|
||||
nNumberOfBytesToRead: u32,
|
||||
lpNumberOfBytesRead: *mut u32,
|
||||
lpOverlapped: *mut std::ffi::c_void,
|
||||
) -> i32;
|
||||
fn WriteFile(
|
||||
hFile: isize,
|
||||
lpBuffer: *const u8,
|
||||
nNumberOfBytesToWrite: u32,
|
||||
lpNumberOfBytesWritten: *mut u32,
|
||||
lpOverlapped: *mut std::ffi::c_void,
|
||||
) -> i32;
|
||||
fn FlushFileBuffers(hFile: isize) -> i32;
|
||||
}
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
fn InitializeSecurityDescriptor(pSecurityDescriptor: *mut u8, dwRevision: u32) -> i32;
|
||||
fn SetSecurityDescriptorDacl(
|
||||
pSecurityDescriptor: *mut u8,
|
||||
bDaclPresent: i32,
|
||||
pDacl: *mut std::ffi::c_void,
|
||||
bDaclDefaulted: i32,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct SECURITY_ATTRIBUTES {
|
||||
nLength: u32,
|
||||
lpSecurityDescriptor: *mut u8,
|
||||
bInheritHandle: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Set up logging
|
||||
tracing_subscriber::fmt()
|
||||
@@ -231,40 +279,43 @@ fn run_pipe_server() -> Result<()> {
|
||||
tracing::info!("Starting pipe server on {}", PIPE_NAME);
|
||||
|
||||
loop {
|
||||
// Create the pipe with security that allows all authenticated users
|
||||
let pipe = unsafe {
|
||||
// Create a security descriptor that allows everyone
|
||||
let mut sd = SECURITY_DESCRIPTOR::default();
|
||||
InitializeSecurityDescriptor(
|
||||
PSECURITY_DESCRIPTOR(&mut sd as *mut _ as *mut _),
|
||||
SECURITY_DESCRIPTOR_REVISION,
|
||||
)?;
|
||||
// Create security descriptor that allows everyone
|
||||
let mut sd = [0u8; 256];
|
||||
unsafe {
|
||||
if InitializeSecurityDescriptor(sd.as_mut_ptr(), SECURITY_DESCRIPTOR_REVISION) == 0 {
|
||||
tracing::error!("Failed to initialize security descriptor");
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set NULL DACL = allow everyone
|
||||
SetSecurityDescriptorDacl(
|
||||
PSECURITY_DESCRIPTOR(&mut sd as *mut _ as *mut _),
|
||||
true,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
if SetSecurityDescriptorDacl(sd.as_mut_ptr(), 1, std::ptr::null_mut(), 0) == 0 {
|
||||
tracing::error!("Failed to set security descriptor DACL");
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let mut sa = SECURITY_ATTRIBUTES {
|
||||
nLength: std::mem::size_of::<SECURITY_ATTRIBUTES>() as u32,
|
||||
lpSecurityDescriptor: &mut sd as *mut _ as *mut _,
|
||||
bInheritHandle: false.into(),
|
||||
lpSecurityDescriptor: sd.as_mut_ptr(),
|
||||
bInheritHandle: 0,
|
||||
};
|
||||
|
||||
// Create the pipe name as wide string
|
||||
let pipe_name: Vec<u16> = PIPE_NAME.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
|
||||
// Create the named pipe
|
||||
let pipe = unsafe {
|
||||
CreateNamedPipeW(
|
||||
windows::core::PCWSTR(pipe_name.as_ptr()),
|
||||
pipe_name.as_ptr(),
|
||||
PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
512,
|
||||
512,
|
||||
0,
|
||||
Some(&mut sa),
|
||||
&mut sa,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -277,13 +328,11 @@ fn run_pipe_server() -> Result<()> {
|
||||
tracing::info!("Waiting for client connection...");
|
||||
|
||||
// Wait for a client to connect
|
||||
let connected = unsafe { ConnectNamedPipe(pipe, None) };
|
||||
if connected.is_err() {
|
||||
// ERROR_PIPE_CONNECTED means client connected between CreateNamedPipe and ConnectNamedPipe
|
||||
// That's OK, continue processing
|
||||
let connected = unsafe { ConnectNamedPipe(pipe, std::ptr::null_mut()) };
|
||||
if connected == 0 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
// ERROR_PIPE_CONNECTED (535) means client connected between Create and Connect
|
||||
if err.raw_os_error() != Some(535) {
|
||||
// 535 = ERROR_PIPE_CONNECTED
|
||||
tracing::warn!("ConnectNamedPipe error: {}", err);
|
||||
}
|
||||
}
|
||||
@@ -297,13 +346,14 @@ fn run_pipe_server() -> Result<()> {
|
||||
let read_result = unsafe {
|
||||
ReadFile(
|
||||
pipe,
|
||||
Some(&mut buffer),
|
||||
Some(&mut bytes_read),
|
||||
None,
|
||||
buffer.as_mut_ptr(),
|
||||
buffer.len() as u32,
|
||||
&mut bytes_read,
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if read_result.is_ok() && bytes_read > 0 {
|
||||
if read_result != 0 && bytes_read > 0 {
|
||||
let command = String::from_utf8_lossy(&buffer[..bytes_read as usize]);
|
||||
let command = command.trim();
|
||||
|
||||
@@ -334,15 +384,16 @@ fn run_pipe_server() -> Result<()> {
|
||||
|
||||
// Write response
|
||||
let mut bytes_written = 0u32;
|
||||
let _ = unsafe {
|
||||
unsafe {
|
||||
WriteFile(
|
||||
pipe,
|
||||
Some(response.as_bytes()),
|
||||
Some(&mut bytes_written),
|
||||
None,
|
||||
)
|
||||
};
|
||||
let _ = unsafe { FlushFileBuffers(pipe) };
|
||||
response.as_ptr(),
|
||||
response.len() as u32,
|
||||
&mut bytes_written,
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
FlushFileBuffers(pipe);
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect and close the pipe
|
||||
|
||||
Reference in New Issue
Block a user