On windows, is it possible to run a single goroutine as a different user?

Issue

How do you delegate the running of a goroutine to another non administrator account on windows? I see you can do this on Linux using syscall.Setuid(). I can’t see how to do this on Windows using the windows syscall package. I’d like to be able to set the account the goroutine runs under while the program is running. Is this possible?

Bit of background :- I want to switch the user that runs the goroutine so I can change the OS User passed to Oracle during the database connection when I use go-oci8 (See my other question). I need to connect to the database and it uses the logged in user (OS User) as part of the security. In java I can change the environment variable during connection set up (or flick the username environmental variable if only connecting for a single user).

I have the users database username (this matches the OS user name) and I get the database user password. I don’t have the users windows login password. I was hoping to be able to delegate running a goroutine to the required windows user from the main go program running as admin in a similar way to Linux port binding example I highlighted. Changing the Oracle login to not use OS User is not an option so it will be back to Java if I can’t work it out 🙁 .

Solution

In theory, no, it is not possible because both on Linux and Windows the concept of user’s identity only exists for OS-level threads and goroutines are not OS threads—instead, they are very light-weight entities which are mapped to real OS threads by the Go scheduler (a part of the Go runtime built into your executable), and during its lifetime a goroutine might be executed on different OS threads at different times.

But there exist a sort of an “exit hatch” for your situation originally designed to help calling into C code: runtime.LockOSThread(). Once a goroutine calls this function it’s stuck to the thread it’s currently running on and won’t be scheduled to be called on another no matter what until the goroutine exits or calls runtime.UnlockOSThread().

You might use this like this:

go func() {
  runtime.LockOSThread()
  defer runtime.UnlockOSThread()
  impersonate() // acquires and assumes some other credentials
  ...
}

The implementation of that imaginary impersonate() function is out of the scope of this question; you can call any Win32 API function using the syscall package—see the standard Go library for examples.


Note that calling runtime.LockOSThread() in real-world scenarious results in dedicating a whole OS thread to just a single goroutine (while usually a whole lot of them runs on just a single one) so if you plan to spawn a lot of such goroutines locked to OS threads be prepared to deal with increased OS resource usage.

Update: a working example tested on Windows XP Pro SP3 32-bit with Go 1.2.1/i386.

It hard codes the user “foo” identified by the password “foo”. To quickly create a user on Windows, do

net user foo * /ADD

and type its password twice when prompted.

Answered By – kostix

Answer Checked By – Katrina (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.