mullvad / windows-service-rs

Windows services in Rust
Apache License 2.0
505 stars 81 forks source link

`ServiceManager::remote_computer()` Doesn't Seem to Be Connecting to a Remote Computer #103

Open jeffenns opened 1 year ago

jeffenns commented 1 year ago

I write a quick test application to learn about your crate (I've never used it before). It worked great for a local computer. However, when using a remote computer it just seems to be operating on the local computer. I don't get any errors or any indication of failures. I've attached a screenshot of the code snippet and output showing the executable in action. I can query the winrm service local and remote at the beginning and they are both stopped. I start it on the local computer only and rerun the queries and they both return that both services are running.

Am I doing something wrong or is remote_computer not behaving like it should? I have been running this as a Domain Admin.

Please, will you let me know if there's anything I can provide to further help looking into this issue? I'd like to use this for a project, but I require remote_computer() to function. Thank you very much!

use std::ffi::OsStr;
use clap::Parser;
#[cfg(windows)]
use windows_service::{
    service::ServiceAccess,
    service_manager::{ServiceManager, ServiceManagerAccess},
};

mod arguments;
mod state;
use arguments::Arguments;
use state::State;

fn main() {
    let args = Arguments::parse();

    let service_name = args.name;
    let manager_access = ServiceManagerAccess::CONNECT;
    let service_manager = if let Some(computername) = args.computername {
        println!("Computer name {}", computername);
        let computername_osstr = OsStr::new(&computername);
        ServiceManager::remote_computer(computername_osstr, None::<&str>, manager_access)
            .expect("Failed to connect to remote computer")
    } else {
        println!("Computer name <localcomputer>");
        ServiceManager::local_computer(None::<&str>, manager_access)
            .expect("Failed to connect to local computer")
    };

    let service = service_manager
        .open_service(service_name.as_str(), ServiceAccess::all())
        .expect("Failed to open service.");

    if let Some(state) = args.state {
        match state {
            State::Start => {
                println!("Starting service");
                service.start(&[""]).unwrap();
            }
            State::Stop => {
                println!("Stopping service");
                service.stop().unwrap();
            }
            State::Pause => {
                println!("Pausing service");
                service.pause().unwrap();
            }
            State::Resume => {
                println!("Resuming service");
                service.resume().unwrap();
            }
        }
    }

    println!("{:?}", service.query_status().unwrap().current_state);
}

redacted_output.log

pronebird commented 1 year ago

Hi,

I think we never fully implemented it to work with remote machine. I looked at OpenSCManager and it has the following remark at the bottom:

If the current user does not have proper access when connecting to a service on another computer, the OpenSCManager function call fails. To connect to a service remotely, call the LogonUser function with LOGON32_LOGON_NEW_CREDENTIALS and then call ImpersonateLoggedOnUser before calling OpenSCManager. For more information about connecting to services remotely, see Services and RPC/TCP.

That's being said, you either have to warm up the SCManager and login to remote machine before creating ServiceManager or someone would have to be generous enough to patch the crate to either do that before connecting to remote machine, or provide a helper to do that.

faern commented 1 year ago

That complexity does not sound like something that windows-service should be responsible for. Less black magic and more control to the developer if they do it themselves before calling into this library. But it sounds like you found the reason for this issue maybe.. Or it's a bit strange that it does not report an error but rather just connect locally?

You can try inserting some debug information into this library and see if we even call OpenSCManagerW with the correct arguments or not.

pronebird commented 1 year ago

It definitely should error if it cannot connect to remote machine. I'd try setting database name to ServicesActive (WinAPI constant [C] SERVICES_ACTIVE_DATABASE) along with the name of remote computer to see if that makes any difference.