I have a windows service "Service1" configured to log on as "Local Service".
I built a console application to start it programmatically.
var service = new ServiceController("Service1");
service.Start();
I know that if I run the ConsoleApplication1 from an administrator command prompt it starts smoothly.
And if I run it without elevation I get an:
System error 5 has occurred.
Access is denied.
But, I need to start it without elevation.
Is it possible, or I have to change the way to achieve this?
You can set the ACL for the service itself to allow this. The SetACL.exe utility makes this (somewhat) straightforward; e.g.:
SetACL.exe -on "MyService" -ot srv -actn ace -ace "n:S-1-5-32-545;p:start_stop"
This allows members of the Users group (S-1-5-32-545) to start and stop MyService.
I followed torak link and I understand this key difference concerning rights in a service:
a service has rights concerning the "Run as" user
a service has different permission to control the service (i.e. to start/stop it)
So, to start the service I need to modify the service control permission.
Well, I have done a windows service called Service1 and I made an installer with WIX.
During setup I call ServiceInstall
<ServiceInstall Id="ServiceInstaller" Type="ownProcess" Vital="yes"
Name="Service1" DisplayName="Service1"
Description="Service1 description"Start="demand"
Account="NT AUTHORITY\LocalService"
ErrorControl="ignore" Interactive="no" >
</ServiceInstall>
Then I have a client program called TestProgram where I try to start the service:
var service = new ServiceController("Service1");
service.Start();
And obviously it doesn't start the service without elevation of TestProgram (that runs under a normal user account).
So the solution is to instruct WIX to allow members of the user group (for example) to start/stop the service, using the PermissionEx tag:
<util:PermissionEx User="Users" ServiceStart="yes" ServiceStop="yes">
</util:PermissionEx>
Hope this helps. Thank you all.
If i can add my 2 cents, here is my solution that wont require any complex App.Manifest or Windows Service modification.
The concept is simply to call "Net Start" through a process that is elevated :
public string StartServiceViaProcess(string param_strServiceName)
{
try
{
const int ERROR_CANCELLED = 1223; //The operation was canceled by the user.
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Verb = "runas";
startInfo.UseShellExecute = true;
startInfo.Arguments = "/C net start " + param_strServiceName;
process.StartInfo = startInfo;
try
{
Process.Start(startInfo);
}
catch (Win32Exception ex)
{
if (ex.NativeErrorCode == ERROR_CANCELLED)
return "L'usager a annulé la demande d'exécution avec privilège.";
else
throw;
}
}
catch (Exception ex)
{
return ex.SI_ConvertToString();
}
return "";
}
I don't think you can do it - It is my understanding that this is due to security reasons. Allowing malware to automatically elevate itself would be problematic.
This is the link that I followed and solved my issue.
How to Grant non-Administrators Rights to Manage Services
By default, common users with no system administrator privileges
cannot manage Windows services. It means that they cannot stop, start
or change the settings or permissions for such services. In some
cases, it is necessary that a user had the permissions to restart or
manage certain services. In this article, we’ll consider some ways to
manage permissions for Windows services. In particular, we’ll show how
to grant a standard user without administrative rights the permissions
to start and stop a specific service...
There is no simple and convenient integrated tool to manage services
permissions in Windows. We’ll consider some ways to grant a user
permissions to manage service...
Related
How I can get list COM+ services running on remote servers? and how to set identity to com+ server remotely.
You can use the COM+ Administration API to accomplish this. It allows you to administer services in the local or remote catalog. See this article for guidance on how to get and set properties. Here's a simple example written in C#. You will add a reference to the COM + 1.0 Admin Type Library
using COMAdmin;
COMAdminCatalogCollection applications;
COMAdminCatalog catalog;
catalog = new COMAdminCatalog();
// To connect to a remote server you would user the following
catalog.Connect(serverName);
applications = (COMAdminCatalogCollection)catalog.GetCollection("Applications");
applications.Populate();
foreach (COMAdminCatalogObject application in applications)
{
//do something with the application
if (application.Name.Equals("MyAppName"))
{
application.Value["Identity"] = #"MACHINE\UserName";
application.Value["Password"] = #"UserPassword";
}
}
I am newly learning IIS, and I am trying to use IIS to host an app to impersonate an Administrative user, then execute powershell command as Admin to add users to local groups.
Within in ASP.NET code, I am running the following:
private string RunScript()
{
StringBuilder stringBuilder = new StringBuilder();
PowerShell psExec = PowerShell.Create();
psExec.AddCommand(SCRIPT_LOCATION);
psExec.AddParameter("username",Username.Text);
psExec.AddParameter("computer", Computer.Text);
psExec.AddParameter("group", Group.Text);
Collection<PSObject> results;
stringBuilder.AppendLine(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
results = psExec.Invoke();
//errors = psExec.Streams.Error.ReadAll();
foreach (PSObject result in results)
{
stringBuilder.AppendLine(result.ToString());
}
return stringBuilder.ToString();
}
In my web.config, I have the following added:
<authentication mode="Windows" />
<identity impersonate="True" userName="<My admin user name>" password="<My admin password>"/>
So my GetCurrent().Name seems to return that I am at least running the application as my admin username. But when calling my powershell script:
Write-Output whoami
Returns that I am NT Authority\System.
In my IIS:
Application pool Identity is "LocalSystem"
Authentication setting has ASP.NET Impersonation (where admin user is set as Specific user) is enabled.
Windows Authentication is enabled.
So when I try to add the user to group, I get "Access is denied". Just as a sanity check, I have confirmed that if I run the powershell script separately as Admin, the add works fine.
I am sure it's something basic I am missing, but if anyone would please provide any advice or guidance, I would greatly appreciate it.
Thank you for your time.
As far as I know, the psExec.Invoke() method creates a thread called “Pipeline Execution Thread” and the command/script is executed in this new thread. By default the impersonation token does not flow across threads, so “Pipeline Execution Thread” doesn’t get the impersonation token of the calling thread.
You can configure ASP.Net to flow the impersonation token to newly created threads by using “alwaysFlowImpersonationPolicy” and “legacyImpersonationPolicy” configuration elements in asp.config file like this:
<runtime>
<legacyImpersonationPolicy enabled=”false”/>
<alwaysFlowImpersonationPolicy enabled=”true”/>
</runtime>
More details about how to set it, you could refer to below article:
https://weblogs.asp.net/owscott/setting-an-aspnet-config-file-per-application-pool
I'm testing using a gMSA account to run an SF app, instead of NETWORKSERVICE.
Following the instructions from here:
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-application-runas-security
Created the gMSA on the domain controller using the powershell cmdlet:
New-ADServiceAccount -name MySA$ -DnsHostName MySA.contoso -ServicePrincipalNames http/MySA.contoso -PrincipalsAllowedToRetrieveManagedPassword Node0Machine$, Node1Machine$, Node2Machine$
Install-AdServiceAccount returned an "unspecified error" on each of the nodes, however Test-AdServiceAccount returns true for MySA$ (when running powershell as a domain user)
ApplicationManifest.xml has the following changes:
<Principals>
<Users>
<User Name="MySA" AccountType="ManagedServiceAccount" AccountName="Contoso\MySA$"/>
</Users>
</Principals>
<Policies>
<SecurityAccessPolicies>
<SecurityAccessPolicy ResourceRef="ConfigurationEncipherment" PrincipalRef="MySa" ResourceType="Certificate" />
</SecurityAccessPolicies>
<DefaultRunAsPolicy UserRef="MySA"/>
</Policies>
The Service Fabric explorer shows the following error for each service:
Error event: SourceId='System.Hosting', Property='CodePackageActivation:Code:SetupEntryPoint'.
There was an error during CodePackage activation.Service host failed to activate. Error:0x8007052e
I have also tried creating the cluster using the gMSA (we are using X509 successfully at the moment). Using the gMSA cluster config as a template, it fails with a timeout (presumably the "WindowsIdentities section is incorrect - there seems to be little documentation on this)
"security": {
"WindowsIdentities": {
"ClustergMSAIdentity": "MySA$#contoso",
"ClusterSPN": "http/MySa.contoso",
"ClientIdentities": [
{
"Identity": "contoso\\MySA$",
"IsAdmin": true
}
]
},
The Error:0x8007052e may be linked to a logon failure.
According to Secure a standalone cluster on Windows by using Windows security and Connect to a secure cluster
If you have more than 10 nodes or for clusters that are likely to grow or shrink. Microsoft strongly recommend using the Group Managed Service Account (gMSA) approach.
You will see also:
You can establish trust in two different ways:
Specify the domain group users that can connect.
Specify the domain node users that can connect.
[...]
Administrators have full access to management capabilities (including read/write capabilities). Users, by default, have only read access to management capabilities (for example, query capabilities), and the ability to resolve applications and services.
You may also find help on Getting Started with Group Managed Service Accounts
According to your comment, as soon as you add the gMSA to the ServiceFabricAdministrators group everything will work and it is probably due to the fact that "administrators have full access to management capabilities"
When opening a sql connection to a local database in a traditional console app I have no issues, however when I attempt to do the same thing within a stateless service running in Service Fabric I get a login error.
The error I receive is "Login failed for user 'WORKGROUP\\NICK$'."
And this is the code I'm using to connect
using (var con = new SqlConnection("Server=.;Trusted_Connection=True;Database=AddressBook"))
{
try
{
con.Open();
}
catch (Exception e)
{
}
}
When I try to add that user to sql server it tells me that the user cannot be found.
Based on the comments above I learned that Service Fabric is running under the NETWORK SERVICE account.
The solution is to update the User Mapping and role membership for the databases that you want to access within the SF cluster.
In SSMS expand Security, Logins, right click NETWORK SERVICE and then choose properties. Under User Mapping place a checkbox next to each Database that you want to expose access to and down below public, db_datareader/writer.
A comment to the accepted answer mentions running your service as a different user account. Here's how to do that. In your ApplicationManifest.xml file, insert this:
<Principals>
<Users>
<User Name="AcctToUse" AccountType="DomainUser"
AccountName="MyDomain\MyUsername" Password="MyPassword" />
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="AcctToUse" />
</Policies>
Edit: I didn't make it clear, AcctToUse is just a string that you make up. It's a key that points to the User. The AccountName field on the other hand is the username.
We are running TFS and Release Management on premises, and i want to deploy my applications to a remote datacenter.
Access is over the internet, so there is no windows shares available.
I am using the vNext templates, and afaik RM seems to only support unc paths over windows shares.
How can i use Release Management to deploy software to this datacenter?
Im working on this solution:
Use WebDav on a IIS located inside the datacenter.
RM server and Target can use the WebDav client built into windows and access it by an unc path.
I haven't gotten this to work yet, as RM won't use the correct credentials to logon to the webdav server.
Updated with my solution
This is only a proof of concept, and is not production tested.
Setup a WebDav site accessible from both RM server and Target server
Install the feature "Desktop experience" on both servers
Make the following DLL
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using Microsoft.TeamFoundation.Release.Common.Helpers;
using Microsoft.TeamFoundation.Release.Composition.Definitions;
using Microsoft.TeamFoundation.Release.Composition.Services;
namespace DoTheNetUse
{
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IThreadSafeService))]
public class DoTheNetUse : BaseThreadSafeService
{
public DoTheNetUse() : base("DoTheNetUse")
{}
protected override void DoAction()
{
Logger.WriteInformation("DoAction: [DoTheNetUse]");
try
{
Logger.WriteInformation("# DoTheNetUse.Start #");
Logger.WriteInformation("{0}, {1}", Environment.UserDomainName, Environment.UserName);
{
Logger.WriteInformation("Net use std");
var si = new ProcessStartInfo("cmd.exe", #"/c ""net use \\sharedwebdavserver.somewhere\DavWWWRoot\ /user:webdavuser webdavuserpassword""");
si.UseShellExecute = false;
si.RedirectStandardOutput = true;
si.RedirectStandardError = true;
var p = Process.Start(si);
p.WaitForExit();
Logger.WriteInformation("Net use output std:" + p.StandardOutput.ReadToEnd());
Logger.WriteInformation("Net use output err:" + p.StandardError.ReadToEnd());
}
//##########################################################
Logger.WriteInformation("# Done #");
}
catch (Exception e)
{
Logger.WriteError(e);
}
}
}
}
Name it "ReleaseManagementMonitor2.dll"
Place it in the a subfolder to The service "ReleaseManagementMonitor"
Configure the shared path as the solution below states.
DO NOT OVERWITE THE EXISTING "ReleaseManagementMonitor2.dll"
The reason that this works is MEF.
The ReleaseManagementMonitor service tries to load the dll "ReleaseManagementMonitor2.dll" from all subfolders.
This dll implements a service interface that RM recognises.
It the runs "net use" to apply the credentials to the session that the service runs under, and thereby grants access to the otherwise inaccessible webdav server.
This solution is certified "Works on my machine"
RM does work only with UNC, you are right on that.
You can leverage that to make your scenario work -
In Theory
Create a boundary machine on the RM domain, where your drops can be copied.
The deploy action running on your datacenter can then copy bits from this boundary machine, using credentials that have access on that domain. (These credentials are provided by you in the WPF console)
How this works
1. Have a dedicated machine on the RM server domain (say D1) that will be used as a boundary machine.
2. Define this machine as a boundary machine in RM by specifying a shared path that will be used by your data centre. Go to settings tab in your WPF console, create a new variable - { Key = RMSharedUNCPath, Value = \\BoundaryMachine\DropsLocation }. RM now understands you want to use this machine as your boundary machine.
3. Make sure you take care of these permissions
RM Server should have write permissions on the \\BoundaryMachine\DropsLocation share.
Pass down credentials of domain D1 to the target machine in the data centre (Domain D2), that can be used to access the share.
4. Credentials can be passed down fron the WPF console, you will have to define the following two config variables in the settings tab again.
Key = RMSharedUNCPathUser ; Value = domain D1 user name
Key = RMSharedUNCPathPwd ; Value = password for the user defined above.
PS - Variable names are case sensitive.
Also, to let RM know that you want to use the SharedUNC mechanism, check the corresponding checkbox for the RM server and connect to it via IP and not DNS name as these must be in different domains, i.e.
Try to use Get-Content on local-server then Set-Content on the remote server passing the file contents over;
Could package everything into an archive of some kind.
The Release Management is copying VisualStudioRemoteDeployer.exe to C:\Windows\DtlDownloads\VisualStudioRemoteDeployer folder on the target server then is copying the scripts from the specified location to target server using robocopy.
So you have to give permissions from your target server to your scripts location.
Release Management update 4 supports "Build drops stored on TFS servers"
http://blogs.msdn.com/b/visualstudioalm/archive/2014/11/11/what-s-new-in-release-management-for-vs-2013-update-4.aspx