Registry read permissions - c#

I want to list out all user data sources using c# but I can't do it because I don't have permission to read the registry key. How can I get all user data sources?
I tried below code but no use
private List<string> ENUMDSN()
{
List<string> list = new List<string>();
list.AddRange(ENUMDSN(Registry.CurrentUser));
list.AddRange(ENUMDSN(Registry.LocalMachine));
XElement xmlele = new XElement("list", list.Select(i => new XElement("list", i)));
return list;
}
private IEnumerable<string> ENUMDSN(RegistryKey rootkey)
{
RegistryKey regkey = rootkey.OpenSubKey(#"Software\ODBC\ODBC.INI\ODBC Data Sources");
foreach (string name in regkey.GetValueNames())
{
string value = regkey.GetValue(name, "").ToString();
yield return name;
}
}

"CurrentUser" registry keys doesn't need any specific permission you can read/write without any problem, but if you want to read keys which in the "LocalMachine" subkey you have to have administrator permissions, there is no other way.
EDIT:
If you run your code under IIS you cannot get key values under the "CurrentUser" or "LocalMachine" because IIS Application Pools doesn't run under your "current account" they runs under their "user accounts".
For solution maybe you can change your Application Pool's user account but it's not recommended for some security reasons.

Related

c# service: how to get user profile folder path

I need to get the user directory from within a C# windows service...
...like C:\Users\myusername\
Ideally, I'd like to have the roaming path...
...like C:\Users\myusername\AppData\Roaming\
When I used the following in a console program I got the correct user directory...
System.Environment.GetEnvironmentVariable("USERPROFILE");
...but when I use that same variable in a service, I get...
C:\WINDOWS\system32\config\systemprofile
How can I get the user folder and maybe even the roaming folder location from a service?
Thanks in advance.
I have searched for getting the profile path of user from Windows service. I have found this question, which does not include a way to do it. As I have found the solution, partly based on a comment by Xavier J on his answer, I have decided to post it here for others.
Following is a piece of code to do that. I have tested it on few systems, and it should work on different OSes ranging from Windows XP to Windows 10 1903.
//You can either provide User name or SID
public string GetUserProfilePath(string userName, string userSID = null)
{
try
{
if (userSID == null)
{
userSID = GetUserSID(userName);
}
var keyPath = #"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\" + userSID;
var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(keyPath);
if (key == null)
{
//handle error
return null;
}
var profilePath = key.GetValue("ProfileImagePath") as string;
return profilePath;
}
catch
{
//handle exception
return null;
}
}
public string GetUserSID(string userName)
{
try
{
NTAccount f = new NTAccount(userName);
SecurityIdentifier s = (SecurityIdentifier)f.Translate(typeof(SecurityIdentifier));
return s.ToString();
}
catch
{
return null;
}
}
First, you'll want to use Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
Environment.SpecialFolder.ApplicationData is for roaming profiles.
Find all SpecialFolder enumeration values here: https://msdn.microsoft.com/en-us/library/system.environment.specialfolder(v=vs.110).aspx
As others have noted, the Service will run under the account LocalSystem/LocalService/NetworkService, depending on configuration: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686005(v=vs.85).aspx
A service doesn't log on like a user, unless the service is configured to use a specific user's profile. So it's not going to point to "user" folders.

C# gpresult /r equivalent

I'm writing a small app that checks to see if a computer and current user are members of the appropriate security groups in Active Directory. I stumbled across this question LINK but it looks like it was forgotten and I'm running into the same issues as the OP. The end result is I want to be able to create an array that is very similar to running the following command from a command prompt.
gpresult /r
Here is a code sample that I have tried from the above link, I'm running into the same errors as the OP specifically "out of range" exception" when attempting to set LoggingUser and LoggingComputer. Since I can't get past these errors I'm not even sure if this method is the right route.
GPRsop rsop = new GPRsop(RsopMode.Logging, "root\\RSOP\\Computer");
rsop.LoggingComputer = "MyComputer";
rsop.LoggingUser = "domain\\user";
rsop.LoggingMode = LoggingMode.Computer;
rsop.CreateQueryResults();
rsop.GenerateReportToFile(ReportType.Xml, "C:\\Temp\\test.xml");
I found a roundabout way to accomplish what I needed by reading the registry keys located in "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History" for applied group policies, added them to an ArrayList then checked to see if the list contained the policy I'm interested in.
To make sure these keys are dynamically updated, I removed the machine in question from the GPO group, rebooted and the keys associated with that policy were removed.
ArrayList groupPolicies = new ArrayList();
using (RegistryKey historyKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History"))
{
foreach (string historySubkey in historyKey.GetSubKeyNames())
{
using (RegistryKey guidKey = historyKey.OpenSubKey(historySubkey))
{
foreach (string guidsubkey in guidKey.GetSubKeyNames())
{
using (RegistryKey keyvalue = guidKey.OpenSubKey(guidsubkey))
{
groupPolicies.Add(keyvalue.GetValue("DisplayName"));
//Console.WriteLine(keyvalue.GetValue("DisplayName"));
}
}
}
}
}
if (!groupPolicies.Contains("replacewithyourGPOname"))
{
Console.WriteLine("The machine is not a member of the policy");
}

Deleting registry key based on one of it's values?

I'm working on a simple application to delete user profile entries from the registry, but I've ran into an issue.
So first, I'm getting all the subkeys that are in the ProfileList through the following code:
List<string> KeyList = new List<string>();
RegistryKey ProfileList = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\\Microsoft\Windows NT\\CurrentVersion\\ProfileList\\");
foreach (string ProfileKey in ProfileList.GetSubKeyNames())
{
KeyList.Add(ProfileKey);
}
From there, I'm getting the ProfileImagePath value of each of those keys and adding them to a checked list box:
KeyList.ForEach(delegate(string ProfileKey)
{
ProfileList = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\\Microsoft\Windows NT\\CurrentVersion\\ProfileList\\" + ProfileKey + "\\");
checkedListBox1.Items.Add(ProfileList.GetValue("ProfileImagePath").ToString());
});
Then, when the user clicks the delete button, I want the application to delete the user profiles that are checked. However, I would have to get the value of each checked item (which looks something like C:/Users/Name) and determine which registry keys to delete. I assume I can do this in a foreach loop, but I'm not quite sure how.
What is the best way to go around doing this?
Thanks.
Here you go. You could execute this code when the user clicks a button such as "Delete Selected Users". Here is the shell of the code:
string[] CheckItemsArray = new string[checkedListBox1.CheckedItems.Count+1];
checkedListBox1.CheckedItems.CopyTo(CheckItemsArray, 0);
foreach (string CheckedItem in CheckItemsArray)
{
if (CheckedItem != null)
{
//your deleting logic here
}
}

Remove a 'Deny' rule (permission) from the 'UserChoice' key in the Registry via C#

I am working on File Associations. I have identified that there is a key called UserChoice in:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\[ext].
I have been able to read from and write to the UserChoice key provided that I create it and that it has not already been created by Windows. However, if the UserChoice key has already been created by Windows, then I need to run as Administrator to get access to the key. My ultimate goal is to delete the UserChoice key.
I have noted that Windows places a Deny rule on the UserChoice key which is preventing me from deleting that key. If I can succeed in removing that rule, I believe that I'll be able to delete the UserChoice key. Here is the code that I have tried:
public static void ShowSecurity(RegistryKey regKeyRoot, string user) {
RegistrySecurity security = regKeyRoot.GetAccessControl(AccessControlSections.All);
foreach (RegistryAccessRule ar in
security.GetAccessRules(true, true, typeof(NTAccount))) {
if (ar.IdentityReference.Value.Contains(User) &&
ar.AccessControlType.ToString().ToLower() == "deny") {
security.RemoveAccessRuleSpecific(ar);
regKeyRoot.SetAccessControl(security);
}
}
}
When Windows creates the UserChoice key it adds a security rule for the current user of Type Deny; permission: Special. This rule is not inherited and applies to the UserChoice key only.
With some messing about and running as Administrator I am able to access that RegistryAccessRule. However even running as Administrator, I cannot remove this rule. I have read somewhere in my research that there is not a programmatic way to do it. I can remove this rule via RegEdit. I can also remove the UserChoice key using File Types Manager from NirSoft. So I assume there is some way to do this.
Summary: Is there a way that I can remove the Deny rule so that I can delete the UserChoice key?
Your code example and the revisions suggested in the answer by #ali lead me to a solution for overcoming the security setting that Windows places on the UserChoice key which enabled me to delete that key.
My solution presumes that the UserChoice key is present in the HKEY_CURRENT_USER (HKCU) hive. If that is the case, the user owns the UserChoice key and therefore has the necessary privileges to change the security settings on that key and ultimately delete it. (This means that the user does not need to be a member of the Administrators group.)
The extensionKey parameter of this method is the parent key of the UserChoice key.
static void DeleteUserChoiceKey(RegistryKey extensionKey)
{
const string userChoiceKeyName = "UserChoice";
using (RegistryKey userChoiceKey =
extensionKey.OpenSubKey(userChoiceKeyName,
RegistryKeyPermissionCheck.ReadWriteSubTree,
RegistryRights.ChangePermissions))
{
if (userChoiceKey == null) { return; }
string userName = WindowsIdentity.GetCurrent().Name;
RegistrySecurity security = userChoiceKey.GetAccessControl();
AuthorizationRuleCollection accRules =
security.GetAccessRules(true, true, typeof(NTAccount));
foreach (RegistryAccessRule ar in accRules)
{
if (ar.IdentityReference.Value == userName &&
ar.AccessControlType == AccessControlType.Deny)
{
security.RemoveAccessRuleSpecific(ar); // remove the 'Deny' permission
}
}
userChoiceKey.SetAccessControl(security); // restore all original permissions
// *except* for the 'Deny' permission
}
extensionKey.DeleteSubKeyTree(userChoiceKeyName, true);
}
A quick thought. Does it work if you take ownership og the regKey, before changing the rules on it
public static void ShowSecurity(RegistryKey regKeyRoot, string user)
{
regKeyRoot.OpenSubKey("", RegistryKeyPermissionCheck.ReadWriteSubTree,
RegistryRights.ChangePermissions);
RegistrySecurity security = regKeyRoot.GetAccessControl(AccessControlSections.All);
security.SetGroup( new NTAccount("Administrators") );
security.SetOwner( new NTAccount("ali") ); //Your account name
security.SetAccessRuleProtection(true, false);
regKeyRoot.SetAccessControl(security);
//---------
foreach (RegistryAccessRule ar in security.GetAccessRules(true, true, typeof(NTAccount)))
{
if (ar.IdentityReference.Value.Contains(User) && ar.AccessControlType == AccessControlType.Deny )
security.RemoveAccessRuleSpecific(ar);
}
regKeyRoot.SetAccessControl(security);
}

How to display a registry key(s) in a text box C#

I am having trouble displaying all the registry keys in the startup section for Windows. I want to display all of the registry keys that tell programs to startup in a text box. I have been able to create a directory listing for the HKEY_LOCAL_MACHINE, but I can't manage to narrow it down to the keys listed in the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run directory. Here is my code:
TreeNode localMachineNode = new TreeNode(Registry.LocalMachine.Name);
string[] localMachineSubKeys = Registry.LocalMachine.GetSubKeyNames();
foreach (string key in localMachineSubKeys)
{
TreeNode node = new TreeNode(key, 0, 1);
}
If there is a better way to do this, i'd love to hear about it. Mind you, that is only part of my code.
Use OpenSubKey to open a key using a path:
var runs = Registry.LocalMachine.OpenSubKey(
#"Software\Microsoft\Windows\CurrentVersion\Run");
var valueNames = runs.GetValueNames();
var values = new List<object>();
foreach (var valueName in valueNames)
{
values.Add(runs.GetValue(valueName));
}
Is this what you are after?
var keys = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Run")
.GetSubKeyNames();

Categories

Resources