views:

454

answers:

5

Hi,

Does anybody know how I can programmatically check (using C#) whether my program will be able to read / write a particular registry key (specifically: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run")?

I am asking because my program has the option to enable or disable the 'run at startup' behaviour. I want to disable this option if the current user is not allowed to make changes to the registry. Is this key always allowed to be written by the current user, or is there the possibility that it has been locked down? If the latter, how do I check this?

I have seen several conflicting ways of checking registry permissions - but basically I can't find a way to check a specific key before I try to read it. I would rather perform the check before accessing the key than trying to access it and receive an exception.

Any help is much appreciated.

Tom

A: 

I'm not sure how to it with C#, but with Win32, you would use RegGetKeySecurity(). Maybe there's a C# wrapper? Otherwise, use P/Invoke.

Adam Rosenfield
+4  A: 

One thing you should know about permissions is that they are volatile. That means you could do your security check on the registry key, attempt to add your value only if the check passes, and then still fail with an insufficient access exception because the permissions changed in between when you made the check and when you acted on the results. This is possible even if they are consecutive statements in your program.

Granted security permissions tend to be relatively stable, but the chance still exists. This means that you must have code to handle the security exception, and if you have to do that anyway there's not really any point in making the check in the first place. Instead, put your time into making your exception handler a little bit better.

That said, "boo" to any app that wants to run something at start-up. YAGNI.

Joel Coehoorn
Well, the app does not set itself to run at startup by default, but there is a good chance that the user would want this behaviour anyway, due to the nature / purpose of the product. Better to make it available rather than force the user to do it manually imo.I want the get / set behaviour to utilise the exception handling, but in the options dialog I would rather use something like RunAtStartup.Enabled = Registry.CanWriteToKey(), if you get the idea. It doesn't make much sense to me to turn an exception into a boolean :/
TomFromThePool
+5  A: 

I think you best bet is to just try to add your value to the key, and handle failure gracefully by informing the user they didn't have enough permissions to do that.

If you're writing some sort of administrative tool that is designed to always be run by an administrator, you should indicate that in the manifest. That way your app will elevate at startup (via UAC prompt).

jeffamaphone
+3  A: 

The RegistryPermission class governs the security permissions around reg keys. To check if you may have write access to a permission you use it in the following manner:

RegistryPermission perm1 = new RegistryPermission(RegistryPermissionAccess.Write, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");

You would then use the "Demand" method in a try/catch and return on failure (the raising of a security exception). On success you'd carry on and perform your update. Although this isn't quite what you want, a check on permissions before access, it is the accepted way of ensuring you have the permissions you need before you operate on the keys. In a fully structured manner this would equate to:

try
{
    RegistryPermission perm1 = new RegistryPermission(RegistryPermissionAccess.Write, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
    perm1.Demand();
}
catch (System.Security.SecurityException ex)
{
    return;
}

//Do your reg updates here

EDIT: Thinking on what I mentioned in the comment, here are extension methods to the RegistryPermission class for permission checks:

using System.Security.Permissions;
using System.Security;

public static class RegistryExtensions
{
    public static bool HavePermissionsOnKey(this RegistryPermission reg, RegistryPermissionAccess accessLevel, string key)
    {
     try
     {
      RegistryPermission r = new RegistryPermission(accessLevel, key);
      r.Demand();
      return true;
     }
     catch (SecurityException)
     {
      return false;
     }
    }

    public static bool CanWriteKey(this RegistryPermission reg, string key)
    {
     try
     {
      RegistryPermission r = new RegistryPermission(RegistryPermissionAccess.Write, key);
      r.Demand();
      return true;
     }
     catch (SecurityException)
     {
      return false;
     }
    }

    public static bool CanReadKey(this RegistryPermission reg, string key)
    {
     try
     {
      RegistryPermission r = new RegistryPermission(RegistryPermissionAccess.Read, key);
      r.Demand();
      return true;
     }
     catch (SecurityException)
     {
      return false;
     }
    }
}
Wolfwyrd
Thanks wolfwyrd :)
TomFromThePool
No problem, and to get the functionality in the style to the comment on Joel Coehoorn's answer, you can always wrap this try/catch in a method on your class (or as an extension method to Registry maybe) and return the true/false that you want to see
Wolfwyrd
^^ Just done that now :P
TomFromThePool
A: 

Just try to open the registry key with WRITE permissions.

That said, what others have said is right: There is no way to tell if an operation is going to succeed unless you try it. Maybe someon deleted the Run key. Maybe the registry will exceed allocated memory. Maybe the disk failed.

peterchen