I have created a windows application that start\stop windows service
now when i tried to start\stop sq-server engine from my application it throw an exception
when i run my Application as administrator it works
now i can run my application as administrator using app.manifest but the problem is that my client does not have permission as administrator
what type of permission my Application need and how to do that?
public static void start()
{
ServiceController sc = new ServiceController(ServiceName, ServerName);
sc.Start();
sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running);
}
public static void stop()
{
ServiceController sc = new ServiceController(ServiceName, ServerName);
sc.Stop();
sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped);
}
Your app is limited to the permissions of the person running it. If they don't have rights to do something, then neither will your application. You say that your client is not an administrator, so in order for your app to work for them an administrator will have to grant their login the permissions needed to start/stop services.
One of the following needs to happen:
The user needs to get admin rights
An admin needs to assign the user permissions to start/stop
services
Your program will need to be run under alternate credentials
For the 3rd option, this can be done at least a couple different ways:
Shift-right-click an application and it will give you a menu
option to run as another user. This option requires someone to be
there to enter their credentials every time you run the application
this way.
Add the ability for someone to enter their credentials into your
application and then impersonate them in your application when
starting/stopping services. This method would allow you to give
them the option to save their credentials for future use (not saying
that's a good idea though).
Related
Is it possible to make a .NET application always an admin while being run on a user account without a UAC popup? I've spent some time searching for this capability but haven't found any satisfactory answers.
For some background info, users are running a test application in a manufacturing environment where a dongle is plugged into a USB(to serial) port. Sometimes windows messes up the COM port and cycling the port can resolve the issue. We have discovered we can do this programmatically with admin privileges, but we do not want the users to be admins, and we also don't want the users to deal with a UAC popup or, god forbid, click "no" on the UAC popup to disable our capabilities and mess up the entire process.
How do I force my .NET application to run as administrator?
I have found this old thread but their solutions all require the user to be admin or the usual UAC popup.
Is there something we can do to enable this capability or are we forever chained to the UAC prompt? We do own these machines and control the applications and users running on them.
EDIT: We are cycling the COM port using this method:
string ComPortName { get; set; } = "USB Serial Port (COM12)";
private void button1_Click(object sender, EventArgs e)
{
SelectQuery query = new SelectQuery("Win32_PnPEntity", "Name=" + '"' + ComPortName + '"');
ManagementObjectSearcher myDevices = new ManagementObjectSearcher(query);
foreach (ManagementObject item in myDevices.Get())
{
textBox1.AppendText("Disabling port " + ComPortName + Environment.NewLine);
ManagementBaseObject inParams = item.InvokeMethod("Disable", null, null);
Thread.Sleep(3000);
textBox1.AppendText("Enabling port " + ComPortName + Environment.NewLine);
ManagementBaseObject UWFEnable = item.InvokeMethod("Enable", null, null);
Thread.Sleep(3000);
textBox1.AppendText("Finished cycling port " + ComPortName);
}
}
You can't, not without at least an UAC prompt. This is totally unavoidable, otherwise Windows wouldn't have any security if it was possible - it MUST be totally impossible, not just "difficult", to bypass UAC.
Some clues to solve anyway your problem:
You can force your application to always ask for elevation (i.e. make it to require administrative privileges) since the first step. Dangerous, but at least, you won't mess the whole software chain: it would be elevated from start.
You can ask for UAC only when it's really needed (for example, when launching a particular sub-process, or launching your own application in elevated mode while keeping context). Obviously, you'll ask again and again until the elevated subprocess is created: if user click on "No", then you try again to launch it. Annoying, but again, you won't mess up the whole process.
You can write a Windows service, that will run under administrative privileges, to perform the COM cycle task you need. Then, you can invoke this service from non-elevated user space, without requiring any elevation. I would recommend this solution.
No, you cannot.
Imagine the user is a standard user - e.g. a 5 year old daughter
She cannot just become an administrator.
If anyone could just become an administrator - then there's no point in having security. And Windows NT is a secure operating system.
Solution to your problem
The easiest way to solve your problem is to grant Everyone permission to do the thing. Because in order to do it: someone needs permission.
We have discovered we can do this programmatically with admin privileges
You don't mention what actions you are taking programmatically, or what Windows API you're calling.
If it involves a registry key, or file, or service
Grant Modify permission
to the Users group (or the Everyone group if you prefer)
This way the user's then have permission to do these things.
There's no shame in granting your users permissions to do the thing - it's what you want them to do. They should have permissions to do it.
If you care about defense-in-depth, you could follow the priciple of least privilege, and rather than granting everyone permission to do the thing, you can grant it to one user:
the user that a service runs as
the user that a scheduled task runs as
And then you only need to worry about your program communicating with a service (asking it to do the thing), or trigger the scheduled task (so that it can do the thing).
This way it's only the service/task that has permissions - and you grant that service/task the Modify permission on the thing that your standard users are currently denied from.
Imagine Windows XP
Imagine how you would have solved this before UAC:
the user is a standard user
and there is no UAC convenience feature to help them elevate to an administrator
In that case you would have to do one of the above:
grant everyone permission to the registry key, or folder
create a service or scheduled task that does have permission: and have your program ask them to do it
I have a .net/c# web app (web api) with windows authentication. The service is hosted on my local computer, IIS 10. Application pool identity set to me, currently logged in windows user. Computer is in active directory domain.
I want to access shared file using account, currently logged in to the app. File has appropriate permissions. For this purposes I use impersonation like this:
if (HttpContext.Current.User.Identity is WindowsIdentity windowsIdentity)
{
using (windowsIdentity.Impersonate())
{
FileStream stream = new FileStream(#"\\server\share\file.ext", FileMode.Open, FileAccess.Read);
}
}
I logging in with current windows account, the same as set in app pool identity. This works fine with a shared file on a local computer, where the app is hosted. But does not work with a remote shared file, located on another computer. The other computer is in active directory domain too.
From a hosting computer I can access shared file using windows explorer or my browser. Also if I do not impersonate user, .net trying to access shared file with application pool identity account(set to the same user, me) and it succeeded for both, local and remote files.
It also works with impersonated identity got from LogonUser method from advapi32.dll. But it requires user password and I do not want to request password from user, already logged in to app.
What am i doing wrong?
Update: If a shared file located on hosting machine, then logon event generated by windows (security tab in event viewer) shows the right user. If a shared file located on another machine, then logon event generated by windows on this machine shows the anonymous user. So, account somehow lost.
Update 2: Impersonation works if I run site on IIS like localhost(localhost in url). But if I run it using ip or site name it stops working.
Update 3: Wireshark shows the request for getting ticket(to access shared file server) for delegation fails with error "KRB5KDC_ERR_BADOPTION NT Status: STATUS_NOT_FOUND". Delegation for application pool user allowed in AD.
The same ticket(for cifs/fileshareservername) without delegation can be successfully retrieved(wireshark shows) when doing Dir command in cmd. Seems like problem in AD.
Can't for sure if what you're doing is wrong, but I can tell you what I've done to do a very similar thing. My .Net site doesn't have WindowsLogin normally, so I had to make an extra jump that I think you could do to facilitate the same thing, just perhaps not the best answer.
At login ( in my membershipProvider ) I run this code:
try
{
if (LogonUser(user,domain,password, [AD_LOGIN],
LOGON32_PROVIDER_DEFAULT, ref handle))
{
IntPtr tokenDuplicate = IntPtr.Zero;
if (DuplicateToken(handle, SecurityImpersonation,
ref tokenDuplicate) != 0)
{
// store off duplicate token here
}
}
}
finally
{
if (handle != IntPtr.Zero)
{
CloseHandle(handle);
}
}
then when you need to impersonate, do this:
var context = WindowsIdentity.Impersonate(tokenDuplicate);
try
{
// do your file access here
}
finally
{
context.Dispose();
}
I had to do some funny conversion of that tokenDuplicate variable. It's an integer value but pointing at a specific memory address where the token information is stored. It stays good as long as your logged in.
Why you can't do the impersonate directly on your identity, don't know. I just know it worked for me with a token, and that was my method to get a token I could use for impersonation.
It started working for me with the following settings.
IIS:
Application pool identity set to a specific user(let's say IISUser).
Windows authentication enabled for IIS site. Kernel mode enabled (important!).
All other magic is happening in Active directory:
Computer with shared files has an SPN: cifs/%computer_name%.
Hosting computer(where IIS installed) is trusted for delegation. Delegation tab -> Trust this computer for delegation to specified services only -> Use any authentication protocol. Then select SPN from item 1. Important: you should select computer SPN, not IISUser SPN.
IISUser is trusted for delegation for SPN from item 1.
I have a Windows service that runs on my local PC. My operating system is windows 7. I want to Start my service via C# code without going through "Computer Management > Services".
When I run the code below it gives me the following Exception:
"Service {ServiceName} was not found on computer '.'."
ServiceController service = new ServiceController(serviceName);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
// ...
}
I've been through many posts regarding this scenario and all mention that this is a security feature of Windows 7. Is there a way to run this service without middling the Admin Groups?
You're probably running into a UAC problem. You need to add a manifest file to your app the indicates the app must be run as an administrator. This will cause Windows to prompt for elevation when your program runs. Here's an article that walks you through the issue/solution:
http://www.codeproject.com/Articles/17968/Making-Your-Application-UAC-Aware
And a related stackoverflow post:
How do I force my .NET application to run as administrator?
It can be about ur framework couldnt selected. U can select it then refresh ur IIS.
Our setup has an embedded manifest that triggers the UAC before the application starts. (The applications runs as an admin user). However, if the setup needs to install the .NET Framework, we have to continue the setup after a reboot. For this reason, we have to create a registry key in the current user's RunOnce.
Unfortunatly, HKEY_CURRENT_USER points to the Administrator's registry. We need to find out the user that is currently logged in and started the installation. (Th normal USER clicked the setup.exe, an ADMIN entered his details in the UAC prompt. We need to find out who the USER was)
I've tried all the usual methods (Environment.UserName, WindowsIdentity.GetCurrent())
Thanks!
You can use the LsaEnumerateLogonSessions function to retreive what you need. However, it is a winapi C function call. If you need a managed version of it, I belive you can look at the source code for Cassia, which uses this function in its terminal services API. The call should be the same. You can also look here.
Also you can use the NetWkstaUserEnum WINAPI function. You can find a managed wrapper for it here
With Cassia library this code works fine:
ITerminalServicesManager manager = new TerminalServicesManager();
ITerminalServicesSession session = manager.CurrentSession;
string userInfo = session.DomainName + "\\" + session.UserName;
NTAccount account = session.UserAccount;
Run your initial setup.exe as a small executable that puts up a splash screen while invoking your real setup program as a child process. The small EXE is not run as admin and can pass the logged in user name to the child process. The child process invokes UAC and runs in the admin context but already has the logged in username as a command line parameter.
It is not possible to retrieve the original user if your application is ran as Administrator:
If a user launches Setup by right-clicking its EXE file and selecting
"Run as administrator", then this flag, unfortunately, will have no
effect, because Setup has no opportunity to run any code with the
original user credentials. The same is true if Setup is launched from
an already-elevated process. Note, however, that this is not an Inno
Setup-specific limitation; Windows Installer-based installers cannot
return to the original user credentials either in such cases.
Source : InnoSetup Help
As said by Matthew in comments, you should not run your application as Administrator but only trigger UAC when needed in your code.
This returns the name of the logged in Windows User by stripping out the domain:
using System.Security.Principal; // here is the security namespace you need
...
string userName = WindowsIdentity.GetCurrent().Name.Replace("\\", "|");
string[] split = userName.Split(new Char[] { '|' });
lblDebug.Text = (split.Count() > 1) ? split[1] : userName;
I have got a project that can copy files to another client's desktops in my domain.There is 300+ client machine.But there is a problem.When i run this project in a non admin user account in my domain.It cant copy files getting error about Access Denied , user restrictions.I wanna do this program like this , in non admin user account when user start to copy files ;
first my program will get admin access by loggin in my admin user accoun to domain than will copy files.Than logout.How can i do this ? I wanna do this with C#.
I had a similar problem: Production needed to run one of my programs that processes files on a location on the network where they don't have any access.
I ended up using Impersonation, which allowed me to run the file processing thread under a set of credentials set at runtime by my program.
In AD I created a special user account with all required permissions for exclusive use by this program.
I know it’s not at all secure, but it works and the odds that it would even occur to someone to hack my program to get these credentials is remote.
Anyway, look into Impersonation I found these resources helpful:
Safely Impersonating Another User
Brian Low's ImpersonationHelper class
-Jay
You can switch privileges when starting the program from itself or from another program. You can do this with two programs, one that runs as the user account and then launches your privileged application. (or launch itself with a different command line to indicate the different run-mode.)
To launch a program in C# as a different user, do this,
// Create a secure version of the password
SecureString pass = new SecureString();
foreach ( char c in _pass.Text )
{
pass.AppendChar( c );
}
Process process = Process.Start( "PrivilegedProgram.exe", _arguments, _user.Text, pass, _domain.Text );
you need to change the thread to the context of an admin user. How you do that in a secure way is the challenge. This sounds like a quick utility program where the security may not be a big deal, however. Just change the admin's password once the utility has been run.