4

I'm having a problem with the windows service I work on currently. Basically I store some values in HKCU registry (from a GUI tool run as administrator) and from within that GUI I am starting a service. The service uses SYSTEM account to run and I believe that's my problem - I can't access registry keys stored with my GUI tool inside the service, as it points to a different HKCU!

How can I "redirect" the service to use the HKCU of the user it was stored with? (Actually I can pass a user name to the service or SID if someone will point me how to retrieve it in my GUI, but I don't know what should I use to "change" the user to point to the correct one)

@EDIT

I use a static class to access registry, it is used by both GUI and Service and the function to retrieve the base key is (rootKey is string variable holding the subkey name):

private static RegistryKey GetBaseKey(bool writable = false)
        {
            try
            {
                RegistryKey reg = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
                RegistryKey rk = reg?.OpenSubKey("SOFTWARE", writable)?.OpenSubKey(rootKey, writable);

                return rk;
            }
            catch (Exception ex)
            {
                // handle exceptions later
            }

            return null;
        }

I have found WindowsIdentity class which can provide a handle (AccessToken) for current user, should I pass it as an argument to my service and use this handle to impersonate inside the service?

@EDIT2

I have done some stuff but it doesn't work. What I tried:

CurrentUserToken = WindowsIdentity.GetCurrent().Token; // to get current identity token

then with ServiceController.Start I added CurrentUserToken.ToString() as an argument. Within my service I initialized RegistryUserToken (IntPtr) with the passed value and I'm stuck at:

WindowsIdentity RegUser = new WindowsIdentity(RegistryUserToken)

throwing exception

Invalid token for impersonation - it cannot be duplicated

I tried the same with AccessToken of current instance of WindowsIdentity - same exception thrown

Can I at all go that way? Or should I try something different??

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
pzaj
  • 1,062
  • 1
  • 17
  • 37
  • Show your code. How do you work with registry? – Yeldar Kurmangaliyev Nov 18 '15 at 10:35
  • Added the "main" registry method, all other methods use it to obtain the subkey to work on. – pzaj Nov 18 '15 at 10:41
  • You can simply run a Windows service under your user account. – Yeldar Kurmangaliyev Nov 18 '15 at 10:42
  • I could, but it's possible to install the service (GUI installs/uninstalls, starts/stops the service) using one user account and configure (store required registry values) using a different account, later then launch it using that different account - this will still make those stored values inaccessible – pzaj Nov 18 '15 at 10:44

3 Answers3

6

I can give you two options: impersonate that user if you have their credentials or use idea that HKCU is a symbolic link for one of the keys under HKEY_USERS. For impersonating you can see this link. If you know the SID of that user, then you can find it in there. You can get the SID as so:

var account = new NTAccount("usernameThatYouNeed");
var identifier = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));
var sid = identifier.Value;

I prefer impersonate. The second option is for case if you don't know that user's credentials. I dislike second option because it requires administrative rights to write in someone else's account.

Yuriy Zaletskyy
  • 4,983
  • 5
  • 34
  • 54
  • Actually I believe I could use impersonation since I launch GUI first (as administrator), with the GUI tool i store those values (in HKCU registry) and from within that GUI I start the service, therefore I can (can I?) retrieve current user identity within GUI code and pass to a service, isn't that correct? – pzaj Nov 18 '15 at 10:46
  • updated my question with what I've done and where I'm stuck, hopefully you'd help me on that. – pzaj Nov 18 '15 at 12:08
5

I needed to read registry of another user from a service. This is how I got it working, but in this case I know exact user name. Other answers here helped a lot. Username and path are whatever you need.

        NTAccount f = new NTAccount("yourUserName");
        SecurityIdentifier s = (SecurityIdentifier)f.Translate(typeof(SecurityIdentifier));
        String sidString = s.ToString();

        Microsoft.Win32.RegistryKey OurKey = Microsoft.Win32.Registry.Users;
        OurKey = OurKey.OpenSubKey(sidString + "\\SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings", true);

        if (OurKey != null) { 
            foreach (string Keyname in OurKey.GetSubKeyNames())
            {
Dimitar Vukman
  • 421
  • 6
  • 15
3

Alright, I've managed to solve it going a bit different way. I've added SID variable to my Registry class and if it's not null then I open Users Registry Hive instead of HKCU. First I retrieve current's user SID (within my GUI application) using:

WindowsIdentity.GetCurrent().User.ToString();

which I pass as an argument to my service and set it for Registry class.

pzaj
  • 1,062
  • 1
  • 17
  • 37