I am trying to check if I have write access to a specific key in the registry before displaying a form that allow the user to change some settings that are written in that key.
code sanitized for clarity
public bool CanWrite()
{
string key = #"HKEY_LOCAL_MACHINE\SOFTWARE\MyHaccpPlan, Inc.\2.0";
try
{
RegistryPermission permission = new RegistryPermission(RegistryPermissionAccess.Write, key);
permission.Demand();
return true;
}
catch(SecurityException)
{
return false;
}
}
I am running the application using a user that has read access only. The problem is that this function return true, even if the user don't have write access.
Later, a call like
Registry.SetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\MyHaccpPlan, Inc.\2.0", "Language", "fr-CA");
will fail with UnauthorizedAccessException.
How do I properly check for registry rights before attempting to write to it?
Edit
I don't want the current user to be able to write there. I want to use this registry entry as a flag that a feature in the software should be disabled. But if the user is an administrator, I want the software to allow the feature. The goal is that a network administrator could be able to preset the settings and that the users will be unable to change them.
But beside actually writing and waiting for it to crash, I want to check the security using the permission system offered in .NET if that is possible.
You shouldn't rely on .NET code access security for managing access control to the registry; let alone should you have explicit checks in your code. With that approach, the user can still use the registry editor and bypass all your access checks.
Instead, you should use proper ACLs to restrict what users can write to a key.
If you want to test at run-time whether you have access to a key, you should try to open the key for writing, and catch SecurityException (in which case the user running the application has no permission to modify the key).
mmm you can try using a tool like Lutz Roeder's Reflector for viewing the content of the Registry.SetValue Method.
Looking a bit to it, it seems to do it with next line of code:
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
Related
We are trying to build an installer, in Wix, for a product. Part of this product requires the installation of elasticsearch as a service, and getting it running as a service. The service should run under a separate user account.
The first step, getting the user account set up, has been successful. However, in order to allow elasticsearch to run correctly, we need to set up certain Environment variables. In order to reduce the chance of inadvertent user error, we will have to have these variables set under the elasticsearch user, not as machine-wide.
To this end, we need a way to create the variables under the specified user only. However, we have not yet been able to work out a way to do this, either using Wix or a C# extension.
The closest we have come is to query the ManagementObject in C# and discover the SID for our ELASTICUSER. We should, in theory, be able to write another environment variable to the Registry, under "HKEY_USERS\<SID>\Environment", as shown.
var query = new SelectQuery("Win32_UserAccount");
var manObjSearch = new ManagementObjectSearcher(query);
var stringToWrite = string.Empty;
foreach (var envVar in manObjSearch.Get())
{
if (envVar["Name"].ToString().ToUpperInvariant() == "ELASTICUSER")
{
elasticUserSid = envVar["SID"].ToString();
}
}
using (var key = Registry.Users.OpenSubKey(elasticUserSid + "\\Environment"))
{
if (key == null)
{
return;
}
key.SetValue("OurVariable", "Value");
}
However, it appears that the SID is not created in the Registry until the user first logs in.
So, is there any way to use either Wix, or in C# to create an environment variable for a newly created user that has never logged in?
Yes, from C# you can P/Invoke the LoadUserProfile Win32 API function. This will create the user's profile if it does not already exist, and load the user's registry hive.
I would not recommend this approach for an account that will be used for interactive logons, but it should be safe enough for a service account.
I am trying to add a registry key in my C# code under
HKEY_CLASSES_ROOT\*\shell\blabla
I want the user to be able to send any file to my application, kind of like Open with UltraEdit or so.
I don't have administrator rights and the users won't have administrator privileges, too.
If I am doing that in my C# code as posted below, I get a
System.UnauthorizedAccessException
Registry.SetValue("HKEY_CLASSES_ROOT\\*\\shell\\blabla", null, "FastSearch");
string path = Application.ExecutablePath;
Registry.SetValue("HKEY_CLASSES_ROOT\\*\\shell\\blabla" + "\\Command", null, path + " \"%1\"");
If I run Regedit and attempt to do it manually myself, I get a similar error:
Error! Key could not be created. Error when writing to the registry.
BUT, if I double click a *.reg file that attempts to write the SAME KEY, everything works!
So why is that?
And do I have a chance to get this done through code?
Or should I just change my code to run that *.reg file?
UPDATE:
Actually the *.reg file did not write the SAME KEY as stated above, but
HKEY_CURRENT_USER\Software\Classes\*\shell\blabla
I didn't notice that. It seems as anything added under HKEY_CURRENT_USER\Software\Classes*\shell\blabla is also added to HKEY_CLASSES_ROOT\*\shell\blabla. Sorry for the confusion.
Although the problem is solved already and the reason for successful import of *.reg file was found out also in the meantime in comparison to C# code, here is a complete answer for this question.
HKEY_CLASSES_ROOT Key (short HKCR) as described by Microsoft shows file name extension associations and COM class registration information which are effective for the current user.
The real locations in registry for those keys are:
HKEY_LOCAL_MACHINE\Software\Classes (short HKLM\Software\Classes) containing the defaults for all users using a machine and
HKEY_CURRENT_USER\Software\Classes (short HKCU\Software\Classes) containing the user specific settings which override the default settings from HKLM\Software\Classes.
A registry write to HKEY_CLASSES_ROOT is always redirected to HKLM\Software\Classes. A write access to any key in HKLM requires administrative privileges which is the reason for the error message.
Microsoft recommends to write directly to either HKLM\Software\Classes or to HKCU\Software\Classes depending on changing the defaults or the effective file associations for the current user.
Write operations to keys under HKCU do not require administrative privileges.
HKCR should be used only for reading currently effective settings for file name extension associations and COM class registration information and not for adding or changing them.
I am trying to take ownership and change the ACL of a file in C#, but even as an administrator I am getting the exception:
System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
The user running the program has the ability to take ownership and change permissions through Windows interface.
My code:
string fileName = #"C:\temp\mount\Windows\System32\Boot\en-US\winload.exe.mui";
FileSecurity fileSec = File.GetAccessControl(fileName);
fileSec.SetOwner(WindowsIdentity.GetCurrent().User);
File.SetAccessControl(fileName, fileSec); //exception thrown here
I even added a check to make sure the current user is member of administrator group:
WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);
bool isAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator); //returns true
Background information: I am creating a WinPE image and need to replace the winload.exe.mui file.
Also, the current permissions on this file only give full access to "Trusted Installer".
I am running on Windows 7
I solved this issue by running takeown in a command shell using a System.Diagnostics.Process. Then I was able to set the access control without error.
Strange that takeown works but the equivalent .NET libraries don't.
You can still use File.SetAccessControl() in your new method in place of FileStream.SetAccessControl(). I'd be willing to bet it works, too. MSDN actually recommends this practice:
"While the FileStream class and SetAccessControl can be used on an existing file, consider using the File.SetAccessControl method as it is easier to use."
http://msdn.microsoft.com/en-us/library/system.io.filestream.setaccesscontrol.aspx[^]
I work on a thick-client app that often runs into "issues" accessing network shares. Before doing any IO with the server, my app tests whether the share (usually of the form \\server\share$) exists. This works fine for detecting those scenarios in which the client has lost its connection to the server, but there are still those odd scenarios where the hidden share exists but the user does not have the rights to read from the within the share. Can someone share (no pun intended) the C# code required to test whether the current user can read files on a share? Should I be querying the share's ACL or the files within the share? What if the share is empty? What if the user is a local non-admin in a mixed environment (XP Pro workstation, Windows 2003 server without a domain on a Novell network)?
The easiest way is to just do it (i.e. try to read a file, for example). As Jared mentioned, there is no way to make sure that you will be able to read in the future (network failure, change of permissions, etc).
As far as code goes, you could use the DirectoryInfo class for some attempts at an answer:
string remotePath = #"\\server\share$";
bool haveAccess = false;
DirectoryInfo di = new DirectoryInfo(remotePath);
if (di.Exists)
{
try
{
// you could also call GetDirectories or GetFiles
// to test them individually
// this will throw an exception if you don't have
// rights to the directory, though
var acl = di.GetAccessControl();
haveAccess = true;
}
catch (UnauthorizedAccessException uae)
{
if (uae.Message.Contains("read-only"))
{
// seems like it is just read-only
haveAccess = true;
}
// no access, sorry
// do something else...
}
}
There are many shortcomings in the above code (such as the hard-coded "read-only" test), but it is just an example used to illustrate what you could do. DirectoryInfo has a few other helper methods that you can use to list the files in the folder. If you don't have access, the methods will throw an UnauthorizedAccessException exception which you can use to test why the access failed. Check out the info on GetAccessControl for further details on the exceptions it throws.
The #1 most reliable way to determine if you used to have permission to read from the share is to
Try and read from the share
Handle errors that could occur while reading and consider that a failed attempt
Unfortunately though based on your description you are trying to determine if you will have read permission to the share. There is no way to reliably determine this.
No matter how many ACLs, directories, etc ... you look at the moment you're done looking at them you could lose access to the share via any number of mechanisms. The most obvious one is the network share going down. All you can determine is that you used to have permission to the share.
I'm trying to write to the windows registry at HKEY_CURRENT_USER\Software\appname however I keep getting a permissions error when I attempt to write to the key, I have added the following to my assembly:
[assembly: RegistryPermissionAttribute(SecurityAction.RequestMinimum, Write = #"HKEY_CURRENT_USER\\Software")]
but this has not resolved the issue, is there something else that I should be doing?
I don't suppose it's something as simple as you having opened the key without specifying that you want write access? The OpenSubKey(string) method only gives read-only access.
The RegistryPermissionAttribute is part of the Code Access Security aka CAS, this is a permission system which checks the permission you have inside of the .NET framework, these permissions are defined by the security policy. There are 4 security policies:
Enterprise - policy for a family of machines that are part of an Active Directory installation.
Machine - policy for the current machine.
User - policy for the logged on user.
AppDomain - policy for the executing application domain.
The first 3 are configured in the configuration screen in the .NET Configuration tool, and the last is configured at runtime.
The reason why I explain this first is because the RegistryPermissionAttribute only checks your .NET permissions, it does not check the Operating System permissions.
You could use the System.Security.AccessControl to check the operating system permissions, but to get the permissions you'll probably need to either elevate or impersonate.
Make sure the app runs using the user-account that has enough rights to access the registry.
I don't see an answer or resolution here. I found this question when searching for something else.
The one thing I think that may be needed is that you need to be running as administrator if you're running from the exe. If you're running from VS you'll need to make sure that VS is running as administrator. VS will show "(Administrator) in the window title if it is.
This works for me. With key already there and without it. Without any special assembly attributes.
using System;
using Microsoft.Win32;
namespace WriteToRegistry {
class Program {
static void Main(string[] args) {
const string csRootKey = #"Software\MyCompany\Test";
using (RegistryKey loRegistryKey = Registry.CurrentUser.CreateSubKey(csRootKey)) {
if (loRegistryKey == null)
throw new InvalidOperationException("Could not create sub key " + csRootKey);
loRegistryKey.SetValue("CurrentTime", DateTime.Now.ToString(), RegistryValueKind.String);
}
}
}
}
EDIT: After rereading the question it seems that the problem could be OS permissions.