1) i was trying to create directory programmatically this way
if (!Directory.Exists(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + "\\VoiceRecords"))
{
Directory.CreateDirectory(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + "\\VoiceRecords");
}
the above code works fine when i run my apps in debug mode but after creating setup and when i installed then when the above line execute and try to create folder in my apps installation location then problem start. what would be the best approach to get rid of this prob because i will distribute this setup to 3rd part and they can install my apps any where which i may not know.
2) when i try to save any value in app.config file then i am getting error.
the error screen shot is here.
now i like to show how i am write data to config at runtime
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (config.AppSettings.Settings["localVoiceRecordsPath"].Value != null || config.AppSettings.Settings["localVoiceRecordsPath"].Value.Trim() != "")
{
config.AppSettings.Settings["localVoiceRecordsPath"].Value = SettingsPopup.txtPath.Text.Replace(",", string.Empty);
config.Save(ConfigurationSaveMode.Modified);
SettingsPopup.txtPath.Text = config.AppSettings.Settings["localVoiceRecordsPath"].Value.Replace(",", string.Empty);
}
else
{
config.AppSettings.Settings.Add("localVoiceRecordsPath", SettingsPopup.txtPath.Text.Replace(",", string.Empty));
config.Save(ConfigurationSaveMode.Modified);
SettingsPopup.txtPath.Text = config.AppSettings.Settings["localVoiceRecordsPath"].Value.Replace(",", string.Empty);
}
everything is working fine when i run my apps in debug mode but problem start when i install the apps from setup and then run. i guess some kind of permission related problem occur. looking for best guidance. thanks
EDIT
Problem solved. i run my apps programmatically in admin mode this way
static bool IsRunAsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(id);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (Environment.OSVersion.Version.Major >= 6)
{
if (!IsRunAsAdmin())
{
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
try
{
Process.Start(proc);
}
catch
{
// The user refused the elevation.
// Do nothing and return directly ...
return;
}
Application.Exit(); // Quit itself
}
else
{
Application.Run(new frmMain());
}
}
else
{
Application.Run(new frmMain());
}
}
you need to probably run the app in administrator mode to give it the right permissions.
here is some sample code/explanation how to check to see what mode you are currently in and how to elevate it:
http://code.msdn.microsoft.com/windowsdesktop/CSUACSelfElevation-644673d3
however be robust! make sure you are running on a Vista system or higher before doing this logic otherwise it will break backward compatibility for earlier OS's if you try to execute the UAC/elevation code.
you may even be able to auto elevate using the app manifest/modifying it:
http://msdn.microsoft.com/en-us/library/aa374191(VS.85).aspx
more information about using the app manifest approach:
http://www.aneef.net/2009/06/29/request-uac-elevation-for-net-application-managed-code/
Security permissions. Let your application request administrator access when it's launched.
You can modify your manifest file and use
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Related
I have a service that I wrote that I need to deploy to a number (about 1100) devices. All of these devices are logged in as a regular user, not an administrator.
I can push out the service with our deployment software, which does run as an admin. Our security team does not want this service to run on the Local System account (for obvious reasons). What I've come up with is that the service will install as the Local System, but will then change it's log in account to a virtual user, which then needs access to a folder in Program Files (x86).
What I've found is that if I install the service (using remote admin access) via the command line, I can install the service, but it won't start.
When I look in the event logs, I get an UnauthorizedAccessException error.
This I suspect is because the service is already running under the virtual user which doesn't have access to start the service. So how can I get around this?
In the main class for the service, I have this method, which is supposed to give the user access to the necessary folder:
private void GiveDirectoryAccess(string dir, string user)
{
try
{
DirectoryInfo directoryInfo = new DirectoryInfo(dir);
DirectorySecurity ds = directoryInfo.GetAccessControl();
ds.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.FullControl,
InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
directoryInfo.SetAccessControl(ds);
}
catch (Exception e)
{
SimpleLog.Log(e);
throw;
}
}
This is called right after the service is initialized:
public CheckRALVersionService()
{
InitializeComponent();
// Give directory access
string alhadminPath = System.IO.Path.Combine(pathToFolder, alhadmin);
GiveDirectoryAccess(alhadminPath, serviceUser);
string exeName = System.IO.Path.GetFileName(fullExeNameAndPath);
string tmppath = System.IO.Path.Combine(localdir, tmp);
SimpleLog.SetLogFile(logDir: tmppath, prefix: "debout." + exeName + "_", extension: "log");
watcher = new DirectoryWatcher(pathToFolder, alhadmin);
}
Then, in the ProjectInstaller class, I am changing the user to the virtual user in the serviceInstaller1_Committed method:
void serviceInstaller1_Committed(object sender, InstallEventArgs e)
{
using (ManagementObject service = new ManagementObject(new ManagementPath("Win32_Service.Name='RalConfigUpdate'")))
{
object[] wmiParams = new object[11];
wmiParams[6] = #"NT Service\RalConfigUpdate";
service.InvokeMethod("Change", wmiParams);
}
}
Do I need a helper service to give the access? Can what I want to do be done all within this service?
Thanks in advance.
One option could be to grant the regular user, the permission to start & stop the service.
There is a little tool from Microsoft for that purpose: SubInAcl!
Set Windows Service Permission!
There should be the possibility to do so using group policies as well. That should be a better approach for your use case. On the other hand, the SubInAcl method is easier to test for you. I found an older description here!
To strictly respond to your question:
You can use
System.Io.File.GetAccessControl to get a FileSecurity Class tha can be used to modify the Permissions on filesystem.
The links show some good examples.
BUT that will works ONLY if the user that will run the process will have the right to CHANGE the PERMISSIONS from Windows, if not ====> UnauthorizedAccessException
After sitting on this for a bit, I found a solution. It may not be the most elegant, but it should work for my purposes. I had all of the "parts", but was just doing things in the wrong order.
Previously, I was trying to change the user during the install process, which wasn't working. What I ended up doing was allow the service to install as the LOCAL SYSTEM account, and then change to the virtual account user during the OnStart method of the actual program.
So:
protected override void OnStart(string[] args)
{
string alhadminPath = System.IO.Path.Combine(pathToFolder, alohadmin);
try
{
// Update the service state to start pending
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// Update the logs
eventLog1.WriteEntry("Starting Service", EventLogEntryType.Information, eventId++);
SimpleLog.Info("RAL Config Update Service started");
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// Change the user to the virutal user
using (ManagementObject service = new ManagementObject(new ManagementPath("Win32_Service.Name='RalConfigUpdate'")))
{
object[] wmiParams = new object[11];
wmiParams[6] = serviceUser;
service.InvokeMethod("Change", wmiParams);
}
GiveDirectoryAccess(alhadminPath, serviceUser);
}
catch (Exception e)
{
eventLog1.WriteEntry("Service failed to start", EventLogEntryType.Error, eventId++);
SimpleLog.Log(e);
throw;
}
}
This is working the way it should, and should also satisfy the security procedures. Thanks everyone.
This question already has answers here:
How do I force my .NET application to run as administrator?
(12 answers)
Closed 8 years ago.
I am creating an application that monitors another application, if the application get close the former will restart that, and I have to create a folder in c:\ drive , if i simply run the application nothing happens but when i run that as admin it works as required.
What can I do to make this application automatically start as admin without any prompt, as i want to run this application on start up, just like some antivirus programs which do not ever need admin rights.
public bool IsProcessOpen()
{
string name = "aProgram";
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains(name))
{
return true;
}
}
return false;
}
private void timer1_Tick_1(object sender, EventArgs e)
{
try
{
bool track = false;
track =IsProcessOpen();
if (!track)
{
Process firstProc = new Process();
firstProc.StartInfo.FileName =Application.StartupPath + "\\" + fileName;
firstProc.EnableRaisingEvents = true;
firstProc.Start();
}
}
catch (Exception)
{
}
}
I dont want that the user gets UAC prompt.
in windows there is something called task scheduler, there one can create the task and give the path to any specific program, choose admin rights and when to start etc. attached screenshots for your reference
I can successfully create an Application Pool and an Application plus link them together.
What I am failing to do however is set the applications Windows Authentication to true and Anonymous Authentication to false.
I patched a hodge podge of examples into one to make this work but I keep getting the following error.
This configuration section cannot be used at this path. This happens
when the section is locked at a parent level. Locking is either by
default (overrideModeDefault="Deny"), or set explicitly by a location
tag with overrideMode="Deny" or the legacy allowOverride="false".
Now barring the obvious that overrideMode needs to likely equal Allow. How do I accomplish this?
public static bool CreateApplication(String websiteName, String applicationName, String appDIR,String appPoolName)
{
try
{
ServerManager iisManager = new ServerManager();
if (!applicationName.Contains("/"))
applicationName = "/" + applicationName;
var app = iisManager.Sites[websiteName].Applications.Add(applicationName, appDIR);
app.ApplicationPoolName = appPoolName;
var config = app.GetWebConfiguration();
var anonsection = config.GetSection("system.webServer/security/authentication/anonymousAuthentication", iisManager.Sites[websiteName].Name + applicationName);
//This is where it fails
anonsection["enabled"] = false;
var winsection = config.GetSection("system.webServer/security/authentication/windowsAuthentication", iisManager.Sites[websiteName].Name + applicationName);
winsection["enabled"] = true;
iisManager.CommitChanges();
return true;
}
catch
{
return false;
}
}
Use the following commands from an admin command prompt
%windir%\system32\inetsrv\appcmd unlock config -section:system.webServer/security/authentication/windowsAuthentication
%windir%\system32\inetsrv\appcmd unlock config -section:system.webServer/security/authentication/anonymousAuthentication
This will unlock those config sections.
I have an application, that needs to get the last shutdown time. I have used EventLog class to get the shutdown time. I have separate class file that is designed to read/write event log. ReadPowerOffEvent function is intended to get the power off event.
public void ReadPowerOffEvent()
{
EventLog eventLog = new EventLog();
eventLog.Log = logName;
eventLog.MachineName = machineName;
if (eventLog.Entries.Count > 0)
{
for (int i = eventLog.Entries.Count - 1; i >= 0; i--)
{
EventLogEntry currentEntry = eventLog.Entries[i];
if (currentEntry.InstanceId == 1074 && currentEntry.Source=="USER32")
{
this.timeGenerated = currentEntry.TimeGenerated;
this.message = currentEntry.Message;
}
}
}
}
But whenever it tries to get the event entry count, it throws an IOException saying "The Network Path Not found". I tried to resolve, but I failed. Please help me out...
I think you sent wrong Log name, this worked for me
EventLog myLog = new EventLog();
myLog.Log = "System";
myLog.Source = "User32";
var lastEntry = myLog;
EventLogEntry sw;
for (var i = myLog.Entries.Count -1 ; i >=0; i--)
{
if (lastEntry.Entries[i].InstanceId == 1074)
sw = lastEntry.Entries[i];
break;
}
}
You have to have the "Remote Registry" service running on your machine (or the machine you want to run this app on). I suspect that this service in set to manual start on your machine. You may have to change the setting on this service to automatic.
If this app is going to be running on other machines, you may want to put some logic into your app to check to make sure this service is running first. If it isn't then you will need to start it up through your app.
Note:
The "Remote Registry" service enables remote users to modify registry setting on your computer. By default, the "Startup type" setting for the "Remote Registry" service may be set to "Automatic" or "Manual" which is a security risk for a single user (or) notebook PC user.
So, to make sure that only users on your computer can modify the system registry disable this "Remote Registry" service.
I found a method for copying ntfs permissions information from one existing folder to a newly created one - I'm not sure if it's doing the work it should do. Maybe one can have a look at the method and give some comments:
private static void CopySecurityInformation(String source, String dest)
{
FileSecurity fileSecurity = File.GetAccessControl(
source,
AccessControlSections.All);
FileAttributes fileAttributes = File.GetAttributes(source);
File.SetAccessControl(dest, fileSecurity);
File.SetAttributes(dest, fileAttributes);
}
Thanks for your help,
Daniel
I tried following the OP suggested pattern for copying a file's ACLs and attributes and found a few issues in our application. Hopefully this information helps others.
According to MSDN, using the File.SetAccessControl() method as shown above will not work.
The SetAccessControl method persists only FileSecurity objects that
have been modified after object creation. If a FileSecurity object
has not been modified, it will not be persisted to a file. Therefore,
it is not possible to retrieve a FileSecurity object from one file and
reapply the same object to another file.
It is necessary to make a new FileSecurity object for the destination file and assign to this a copy of the source FileSecurity object.
Here is an example of a pattern that works from our app.
public static void CopyFile(string source, string destination)
{
// Copy the file
File.Copy(source, destination, true);
// Get the source file's ACLs
FileSecurity fileSecuritySource = File.GetAccessControl(source, AccessControlSections.All);
string sddlSource = fileSecuritySource.GetSecurityDescriptorSddlForm(AccessControlSections.All);
// Create the destination file's ACLs
FileSecurity fileSecurityDestination = new FileSecurity();
fileSecurityDestination.SetSecurityDescriptorSddlForm(sddlSource);
// Set the destination file's ACLs
File.SetAccessControl(destination, fileSecurityDestination);
// copy the file attributes now
FileAttributes fileAttributes = File.GetAttributes(source);
File.SetAttributes(destination, fileAttributes);
}
After fixing the first issue, then we found the owner attribute was not being copied. Instead, the destination file was owned by Administrator in our case. To get around that the process needs to enable the SE_RESTORE_NAME privilege. Check out AdjustTokenPrivileges on pinvoke.net for a complete Privileges class that makes setting privileges easy.
The last thing that we had to deal with was UAC. We needed to restart our app with administrative rights if the user is running under UAC. Here is another example from our app that deals with relaunching the app with elevated privileges.
private static void RelaunchWithAdministratorRights(string[] args)
{
// Launch as administrator
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.UseShellExecute = true;
processStartInfo.WorkingDirectory = Environment.CurrentDirectory;
string executablePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
processStartInfo.FileName = executablePath;
processStartInfo.Verb = "runas";
if (args != null && args.Count() > 0)
{
string arguments = args[0];
for (int i = 1; i < args.Count(); i++)
arguments += " " + args[i];
processStartInfo.Arguments = arguments;
}
try
{
using (Process exeProcess = Process.Start(processStartInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
// The user refused to allow privileges elevation. Do nothing and return directly ...
}
Environment.Exit(0);
}
Ours was a console app so we need to pass the args parameter from the Main method to the RelaunchWithAdministratorRights(args). Non-console apps could pass null instead. We call RelaunchWithAdministratorRights from within catch blocks as in:
try
{
...
}
catch (SecurityException)
{
RelaunchWithAdministratorRights(args);
return;
}
In our app we just return after the call to RelaunchWithAdministratorRights to exit the instance of the app that lacked privileges. Depending on your app, you may prefer to throw your way out. Regardless, after returning from RelaunchWithAdministratorRights you don't want this instance to continue processing.
Enjoy!
It does slightly more than just copying the NTFS permissions. It also copies the attributes of the file. I'm not quite certain whether it copies inherited permissions, though, but run it once and you should be able to find out.
Note that copying permissions on and of itself requires special permissions (administrators have these, of course), be sure the process running this method has the required permissions to query, view and set permissions on those objects.