//! Raven Service - Servico Windows para operacoes privilegiadas //! //! Este servico roda como LocalSystem e executa operacoes que requerem //! privilegios de administrador, como: //! - Aplicar politicas de USB //! - Provisionar e configurar RustDesk //! - Modificar chaves de registro em HKEY_LOCAL_MACHINE //! //! O app Raven UI comunica com este servico via Named Pipes. mod ipc; mod rustdesk; mod usb_policy; use std::ffi::OsString; use std::time::Duration; use tracing::{error, info}; use windows_service::{ define_windows_service, service::{ ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, ServiceType, }, service_control_handler::{self, ServiceControlHandlerResult}, service_dispatcher, }; const SERVICE_NAME: &str = "RavenService"; const SERVICE_DISPLAY_NAME: &str = "Raven Desktop Service"; const SERVICE_DESCRIPTION: &str = "Servico do Raven Desktop para operacoes privilegiadas (USB, RustDesk)"; const PIPE_NAME: &str = r"\\.\pipe\RavenService"; define_windows_service!(ffi_service_main, service_main); fn main() -> Result<(), Box> { // Configura logging init_logging(); // Verifica argumentos de linha de comando let args: Vec = std::env::args().collect(); if args.len() > 1 { match args[1].as_str() { "install" => { install_service()?; return Ok(()); } "uninstall" => { uninstall_service()?; return Ok(()); } "run" => { // Modo de teste: roda sem registrar como servico info!("Executando em modo de teste (nao como servico)"); run_standalone()?; return Ok(()); } _ => {} } } // Inicia como servico Windows info!("Iniciando Raven Service..."); service_dispatcher::start(SERVICE_NAME, ffi_service_main)?; Ok(()) } fn init_logging() { use tracing_subscriber::{fmt, prelude::*, EnvFilter}; // Tenta criar diretorio de logs let log_dir = std::env::var("PROGRAMDATA") .map(|p| std::path::PathBuf::from(p).join("RavenService").join("logs")) .unwrap_or_else(|_| std::path::PathBuf::from("C:\\ProgramData\\RavenService\\logs")); let _ = std::fs::create_dir_all(&log_dir); // Arquivo de log let log_file = log_dir.join("service.log"); let file = std::fs::OpenOptions::new() .create(true) .append(true) .open(&log_file) .ok(); let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); if let Some(file) = file { tracing_subscriber::registry() .with(filter) .with(fmt::layer().with_writer(file).with_ansi(false)) .init(); } else { tracing_subscriber::registry() .with(filter) .with(fmt::layer()) .init(); } } fn service_main(arguments: Vec) { if let Err(e) = run_service(arguments) { error!("Erro ao executar servico: {}", e); } } fn run_service(_arguments: Vec) -> Result<(), Box> { info!("Servico iniciando..."); // Canal para shutdown let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>(); let shutdown_tx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_tx))); // Registra handler de controle do servico let shutdown_tx_clone = shutdown_tx.clone(); let status_handle = service_control_handler::register(SERVICE_NAME, move |control| { match control { ServiceControl::Stop | ServiceControl::Shutdown => { info!("Recebido comando de parada"); if let Ok(mut guard) = shutdown_tx_clone.lock() { if let Some(tx) = guard.take() { let _ = tx.send(()); } } ServiceControlHandlerResult::NoError } ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, _ => ServiceControlHandlerResult::NotImplemented, } })?; // Atualiza status para Running status_handle.set_service_status(ServiceStatus { service_type: ServiceType::OWN_PROCESS, current_state: ServiceState::Running, controls_accepted: ServiceControlAccept::STOP | ServiceControlAccept::SHUTDOWN, exit_code: ServiceExitCode::Win32(0), checkpoint: 0, wait_hint: Duration::default(), process_id: None, })?; info!("Servico em execucao, aguardando conexoes..."); // Cria runtime Tokio let runtime = tokio::runtime::Runtime::new()?; // Executa servidor IPC runtime.block_on(async { tokio::select! { result = ipc::run_server(PIPE_NAME) => { if let Err(e) = result { error!("Erro no servidor IPC: {}", e); } } _ = async { let _ = shutdown_rx.await; } => { info!("Shutdown solicitado"); } } }); // Atualiza status para Stopped status_handle.set_service_status(ServiceStatus { service_type: ServiceType::OWN_PROCESS, current_state: ServiceState::Stopped, controls_accepted: ServiceControlAccept::empty(), exit_code: ServiceExitCode::Win32(0), checkpoint: 0, wait_hint: Duration::default(), process_id: None, })?; info!("Servico parado"); Ok(()) } fn run_standalone() -> Result<(), Box> { let runtime = tokio::runtime::Runtime::new()?; runtime.block_on(async { info!("Servidor IPC iniciando em modo standalone..."); tokio::select! { result = ipc::run_server(PIPE_NAME) => { if let Err(e) = result { error!("Erro no servidor IPC: {}", e); } } _ = tokio::signal::ctrl_c() => { info!("Ctrl+C recebido, encerrando..."); } } }); Ok(()) } fn install_service() -> Result<(), Box> { use windows_service::{ service::{ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType}, service_manager::{ServiceManager, ServiceManagerAccess}, }; info!("Instalando servico..."); let manager = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CREATE_SERVICE)?; let exe_path = std::env::current_exe()?; let service_info = ServiceInfo { name: OsString::from(SERVICE_NAME), display_name: OsString::from(SERVICE_DISPLAY_NAME), service_type: ServiceType::OWN_PROCESS, start_type: ServiceStartType::AutoStart, error_control: ServiceErrorControl::Normal, executable_path: exe_path, launch_arguments: vec![], dependencies: vec![], account_name: None, // LocalSystem account_password: None, }; let service = manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?; // Define descricao service.set_description(SERVICE_DESCRIPTION)?; info!("Servico instalado com sucesso: {}", SERVICE_NAME); println!("Servico '{}' instalado com sucesso!", SERVICE_DISPLAY_NAME); println!("Para iniciar: sc start {}", SERVICE_NAME); Ok(()) } fn uninstall_service() -> Result<(), Box> { use windows_service::{ service::ServiceAccess, service_manager::{ServiceManager, ServiceManagerAccess}, }; info!("Desinstalando servico..."); let manager = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT)?; let service = manager.open_service( SERVICE_NAME, ServiceAccess::STOP | ServiceAccess::DELETE | ServiceAccess::QUERY_STATUS, )?; // Tenta parar o servico primeiro let status = service.query_status()?; if status.current_state != ServiceState::Stopped { info!("Parando servico..."); let _ = service.stop(); std::thread::sleep(Duration::from_secs(2)); } // Remove o servico service.delete()?; info!("Servico desinstalado com sucesso"); println!("Servico '{}' removido com sucesso!", SERVICE_DISPLAY_NAME); Ok(()) }