Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determine KDE Connect's DBUS_SESSION_BUS_ADDRESS on Windows #44

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

qwerty12
Copy link

@qwerty12 qwerty12 commented Oct 27, 2021

This adds support for determining KDE Connect's dbus-daemon's session bus's address on Windows. I haven't tested to see if this breaks building on Linux.

Outdated It works like this:
  1. Get a list of processes in the same Windows session as the one kdeconnect-chrome-extension.exe is running in (on a system where multiple users are logged in at the same time, this avoids possibly connecting to the wrong KDE Connect instance)

  2. For any dbus-daemon.exe processes, store their PIDs

  3. Read the system's TCP table and for anything listening to a port bound on 127.0.0.1, see if the PID matches one collected in step 2

  4. If so, call org.freedesktop.DBus.NameHasOwner and see if org.kde.kdeconnect has registered on the bus. If that is the case, the connection string is cached and the connection is returned

See #44 (comment)

If this is acceptable, the remaning two issues for fully fledged Windows support would be to adapt the installer (climenu won't build on Windows) and updating godbus to v5.

(As an aside, if someone's interested in adding macOS support...)

EDIT: This requires a newer version of golang.org/x/sys than the one that is automatically pulled in by glide as a dependency

@qwerty12 qwerty12 force-pushed the windows-dbus-conn branch 7 times, most recently from 3754e8e to e476910 Compare October 28, 2021 03:04
@pdf
Copy link
Owner

pdf commented Oct 28, 2021

Well, this is quite a dance to go through. I do note that kdeconnect-cli.exe works on windows, and I'd be somewhat surprised to discover they were using a similar method. Perhaps it might be possible to work out how they're discovering the bus address?

Also, I vaguely recall it being a requirement to write registry keys to install a native host on windows, do you know off-hand if my recollection is correct, and would that mean we'd need to deal with UAC or something for the installer?

I'm afraid I haven't spent any real time on Windows in decades, so I appreciate the assistance.

@qwerty12
Copy link
Author

qwerty12 commented Oct 28, 2021

Oh, wow, after just now hearing of kdeconnect-cli and trying it myself, I do not disagree. At least this isn't the code where it reads processes' environment variables... But I think have the gist (with assumptions made) of how it works:

  • KDE Connect uses QtDBus, naturally. QtDBus uses the original libdbus so it gets handling of any platform-specific implementation "quirks" for free

  • KDE Connect's D-Bus session.conf is configured with <listen>autolaunch:scope=*install-path</listen>, so the path of where libdbus-1.dll is stored is key - its dirname is used to generate a hash

  • When dbus-daemon.exe starts and reads that specific <listen> value, it creates a Windows Section with the name of DBusDaemonAddressInfo-$HASH containing a valid DBUS_SESSION_BUS_ADDRESS for clients

  • For client programs using the same libdbus as the dbus-daemon.exe, like kdeconnect-cli, libdbus reads the same listen setting and comes up with the same Section name to open and read

Reading the Section and obtaining its contents is trivial. Finding KDE Connect's installation directory is not. There's two issues there:

  • The KDE Connect download page suggests getting it from the Microsoft Store. It installs it to C:\Program Files\WindowsApps\KDEe.V.KDEConnect_0.0.878.0_x64__7vt06qxq7ptv8\ - not exactly determinable. EDIT: I have Go code to get this path, so this isn't a problem any more.

  • But that's not the only way to install KDE Connect. An NSIS-based installer is offered. It offers standard system-wide and per-user paths, but also the choice to install it to an arbitrarily-chosen directory. For the standard paths, they could probably be hardcoded, but otherwise I do not currently know if the NSIS installer stores the installation path in the registry and if so, can it be easily found (no use of random GUIDs etc.). In the case of non-Microsoft Store installs, it might be easier to just get the kdeconnect-chrome-extension installer to ask the user for the path of KDE Connect if it's not found in the usual places and store it in the registry or as an environment variable.

  • EDIT: Alternatively, It would actually be easier to just take the path of the running kdeconnect-indicator.exe...

Once KDE Connect's path has been determined, the hashing can be done in kdeconnect-chrome-extension. I looked at the D-Bus code: you take the location of where libdbus.dll is, dirname() it, strip "\bin" off the end if present, and then make the path (with trailing backslash) lower-case and then just SHA1 the path (and then lower-case the result)

Also, I vaguely recall it being a requirement to write registry keys to install a native host on windows, do you know off-hand if my recollection is correct, and would that mean we'd need to deal with UAC or something for the installer?

You're right, but UAC would only be an issue if you're wanting to do a system-wide install (really, you'd just have to relaunch). Both Chrome (and its derivatives I presume) and Firefox read a per-user registry key on Windows for manifest paths, which doesn't require special privileges to write to.

I'm afraid I haven't spent any real time on Windows in decades, so I appreciate the assistance.

I'm very much appreciative of this. The approach I've used currently may be... well... convoluted but kdeconnect-chrome-extension has saved me time nevertheless on Windows.

@pdf
Copy link
Owner

pdf commented Oct 30, 2021

This is good analysis, not as straight-forward as I was hoping. I'm open to this approach if you agree it would be cleaner than the current method.

I'll sort out the installer stuff once it's decided what the path is here.

@qwerty12
Copy link
Author

qwerty12 commented Oct 30, 2021

I'm not sure on what GitHub PR etiquette is, to be honest, so I've just rebased the branch this PR is pointing to with code that does the Section reading. It is more complex, but the possible race condition between reading the TCP tables and scanning the processes isn't a problem any more. EDIT: unless you're getting something else calling itself kdeconnect-indicator.exe, this way will always connect to KDE Connect's D-Bus daemon too

To try and obtain KDE Connect's path, the following is tried:

  • Using the package manager API to determine if there's a copy of KDE Connect installed from the Windows Store and if so, use its path

  • For any running kdeconnect-indicator.exe/kdeconnectd.exe/kdeconnect-indicator.exe process, take the path of the first match. Should work for installs from elsewhere (or if the Store code fails)

For the Windows Store code, Windows.Management.Deployment is a COM API. The code to utilise it is ugly (but I'm 99.999999% sure I free everything that needs to be freed) and relies on the https://github.com/go-ole/go-ole library.
Maybe it's the way I've written it, but the COM code does look really ugly in Go. It's pretty much the equivalent of this, which is much easier to read.

I've split the path determination code for both ways into separate files for readability purposes. I can merge the code into one file or get rid of a method entirely. Both do not rely on any undocumented code; however, borrowing a trick from syscall_unix.go's Mmap, the code to read from the section does use reflect.SliceHeader to turn the mapped view's uintptr result into a []byte.

Once the path has been found, the hashed version is cached (naïvely - assumes a single thread) to avoid the path lookups. But the Section is always read. IMO the path isn't likely to change, but relaunching KDE Connect (slightly more likely to happen) may cause its dbus-daemon to change ports.

I do not know Go at all, so if there's basic errors or better ways to do things (or even better names for functions or variables), let me know or just have at it. Cheers.

@pdf
Copy link
Owner

pdf commented Nov 5, 2021

Sorry for the delay, been a little busy. I think my preference would be to include only the generic implementation that searches for running processes, since that gives us the best coverage for install methods, and lets us drop a bunch of code. I'll try to find time for a proper review over this weekend.

@qwerty12
Copy link
Author

qwerty12 commented Nov 6, 2021

No worries. Getting rid of the Windows Store-specific code is probably for the best... The one thing I need to add: capping the maximum amount of data read from the Section/Mapping, as I cannot imagine in practice a DBUS_SESSION_BUS_ADDRESS greater than, say, 64Kb. Thanks.

@niks255
Copy link

niks255 commented Jan 24, 2022

  • It installs it to C:\Program Files\WindowsApps\KDEe.V.KDEConnect_0.0.878.0_x64__7vt06qxq7ptv8\ - not exactly determinable.

You should not use that path. And you can't access it easily anyway.
Just use its execution alias, which has a stable path ("C:\Users\yourprofilename\AppData\Local\Microsoft\WindowsApps\kdeconnect-cli.exe" or just determine it from PATH variable, since it has this path added). This will make things much easier.

@qwerty12
Copy link
Author

An execution alias wouldn't help any here. libdbus, when creating its Section with the information that is needed, doesn't use one but does hash the actual path it's in. In any case, getting the actual path isn't a problem any more - it's pulled from the running processes. I did write code to read it from the Windows APIs designed for getting Store applications' information, but removed it following pdf's comments.

@niks255
Copy link

niks255 commented Jan 24, 2022

libdbus, when creating its Section with the information that is needed, doesn't use one but does hash the actual path it's in

Oh, in that case you are doing it right. Sorry.
But the path changes every time the app is updated. Is that going to be a problem?

@qwerty12
Copy link
Author

But the path changes every time the app is updated. Is that going to be a problem?

Yes. This code caches the Section name to open, which, as you point out, is liable to change in the case of an update. I don't consider fixing it a huge priority yet, because there's no way (as far as I can tell) to get this native extension to refresh its connection to KDE Connect's D-Bus daemon anyway*. In the two months I've been running this on Windows, I've only had it mess up once, at which point I just disabled and re-enabled the extension and all was well...

* I assume there's no need for such a thing in Linux, where the Session Bus is provided by the system

@niks255
Copy link

niks255 commented Jan 24, 2022

I've only had it mess up once, at which point I just disabled and re-enabled the extension and all was well...

So basically, it's refreshed every time you restart a browser?

@qwerty12
Copy link
Author

Yes

@pdf
Copy link
Owner

pdf commented Jan 24, 2022

I feel like I need to apologise for the further delays here - I have some of the required changes staged, but I need to replace the installer code with something that will work on Windows and I just haven't made the time yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants