Check Windows services status - what privilege do I need - c#

I want to check some Windows services status on different remote servers like this:
ServiceController sc = new ServiceController("MyWindowsService", "COMPUTER_NAME");
var status = sc.Status
But I don't (and can't) have Administrator privileges on those servers.
What right should I be asking for to check the status ?
I don't wanna be able to restart them either, I need Read access only,
The application isn't running on the same machine.

Non-admin users can connect to the Service Control Manager remotely, provided they have the "Access this computer from the network" user right. By default this right is granted to all users.
Access to individual services is controlled by the ACL on each service. You must already know the service name, because a non-admin user cannot enumerate services remotely.
The default security descriptor for a service is as follows:
D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)
You can determine the security descriptor for a service using the sc sdshow command. The string format is described in Security Descriptor Definition Language on MSDN.
OK, let's expand out that security descriptor string. This is a bit tricky because the mapping between the SDDL permissions and equivalent security manager permissions does not appear to be well documented in MSDN or in the SDK headers; luckily, Wayne Martin has already done the heavy lifting for us and posted the results in the blog entry Service Control Manager Security for non-admins.
D: - this part is the DACL, the permissions on the service.
Since all the entries are allow entries, the order isn't significant; I'll list them from least to most privilege for convenience.
(A;;CCLCSWLOCRRC;;;IU) - allow the interactive user the following rights:
CC - SERVICE_QUERY_CONFIG (the right to query the service configuration)
LC - SERVICE_QUERY_STATUS (the right to query the service status)
SW - SERVICE_ENUMERATE_DEPENDENTS (the right to see service dependencies)
LO - SERVICE_INTERROGATE (the right to send SERVICE_CONTROL_INTERROGATE)
CR - SERVICE_USER_DEFINED_CONTROL (the right to send a user defined control)
RC - READ_CONTROL (the right to see the permissions)
(A;;CCLCSWLOCRRC;;;SU) - allow services the following rights:
same as for the interactive user
(A;;CCLCSWRPWPDTLOCRRC;;;SY) - allow local system the following rights:
same as for the interactive user, plus:
RP - SERVICE_START (the right to start the service)
WP - SERVICE_STOP (the right to stop the service)
DT - SERVICE_PAUSE_CONTINUE (the right to send pause and continue requests)
(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA) - allow the Administrators group:
same as for local system, plus:
DC - SERVICE_CHANGE_CONFIG (the right to reconfigure the service)
SD - DELETE (the right to delete the service)
WD - WRITE_DAC (permission to change the permissions)
WO - WRITE_OWNER (permission to take ownership)
The second part of the security descriptor string (S:(...)) is the SACL, which controls what auditing is done. We're not interested in that at the moment.
You will notice that there are no allow permissions applicable to non-administrative remote users. To give remote access to a particular user, add an allow ACE for that user with the same permissions as the interactive user.
If this is your own service, you can change the permissions when the service is installed using the SetServiceObjectSecurity function. You could also write a program using this function to change the permissions on an existing service.
Alternatively, you can use sc sdset at the command line to set the permissions for an existing service based on a SDDL string. You will first need to look up the SID string for the user; in a domain, you can do this using Active Directory Users and Computers. The SID string can be seen via the Attribute Editor tab, in the objectSid attribute. (Unfortunately you can't copy and paste that way. Suggestions for more convenient methods of looking up a user's SID are welcomed.)
If the SID string were S-1-5-21-131085535662-8349591032-725385543-5981, for example, the command line would be
sc sdset myservice D:(A;;CCLCSWLOCRRC;;;S-1-5-21-131085535662-8349591032-725385543-5981)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)
(You do not need to specify the SACL; if absent, the existing SACL will be retained.)

Related

NT AUTHORITY\Local Service is not listed in the Access Control List of a directory

I'm having this issue where I'm trying to check if NT\Authority Local Service has read\execute permissions on a directory (folder). The product that I work on REQUIRES that the folder the user is installing to has read\execute permissions set for Local Service.
The problem is that when I get the Access Control List (ACL) recursively (groups-within-groups), Local Service is not listed so I can't check if he has permissions to that folder or not.
By default, Local Service does not have read/execute permissions to user profiles (My Documents, Desktop, etc...) but I won't know if Local Service has access to other directories the user chooses to install to.
NOTE: Local Service DOES have access to Program Files, even though it is NOT listed in the ACL. Is it hidden somewhere else?
This is a short snippet on how I'm pulling the ACL:
GroupPrincipal groupPrincipal =
GroupPrincipal.FindByIdentity(principalContext, identityReferenceValue);
// GetMembers(true) is recursive (groups-within-groups)
foreach (var member in groupPrincipal.GetMembers(true)) {
if (member.SamAccountName.Equals("LOCAL SERVICE")) {
foundLocalService = true;
break;
}
}
Is there any other way I should be doing this? (Other than adding an access rule for Local Service on that directory)
Is Local Service just not listed in Directories ACL's?
Any help would be greatly appreciated.
It's notoriously difficult to calculate "effective permissions" for an account. But the simple answer to your question is that you will likely want to look for either on of:
The local Users group, sometimes shown as BUILTIN\Users or COMPUTERNAME\Users, or
Authenticated Users, sometimes shown as NT AUTHORITY\Authenticated Users.
Authenticated Users is one of the well-know SIDs. It is "a group that includes all users whose identities were authenticated when they logged on.". As long as you can prove who you are, you are included in Authenticated Users. The SID for this is always S-1-5-11 on every Windows computer.
However, it's not really considered a real group. To find it when adding permissions to a folder, you have to have "Built-in security principals" selected under "Select this object type":
The local Users group contains Authenticated Users by default. On my computer, I actually see both Users and Authenticated Users in the default permissions on the file system.
That's what you will most likely see, and that's likely all that matters.
But that's not the only way. You could see Everyone (S-1-1-0), which includes every user, authenticated or not.
Or, it could be a file or folder that has the LOCAL SERVICE account as the owner.
Or, there could be a local group that was created manually and LOCAL SERVICE was added to.
One way to get a more authoritative list of what you can look for is to run this under the LOCAL SERVICE account:
whoami /groups
That will tell you every group in the authentication token, which is every group that you are considered a member of for authentication purposes.
But you can't just open a command prompt as LOCAL SERVICE. So one way to do this is to open the Task Scheduler and create a task that runs under LOCAL SERVICE, with the action of:
Program: cmd
Arguments: /c "whoami /groups > C:\temp\localservice.txt"
Then run the task and, when it's done, look at C:\temp\localservice.txt. It will have a table of group names and their SIDs that you can look for.

C# Remove AD Computer Account Running on Windows Service

I want to write a function in a windows service application to remove a given computer name from Active Directory.
The Windows service is running on a machine which is domain-joined to the DC. Currently I have logged in to this machine with domain admin account.
The Windows service is running under the security context of "NT AUTHORITY/SYSTEM" and this should not be changed, as there shouldn't be any user interaction after installing the application, meaning that admin shouldn't enter their credentials in services.
When I run the application with my newly added code to delete the computer account, it doesn't work. However, when I change the logon info on the Windows Service and update that with domain admin credentials, it's able to successfully remove the computer account from AD.
Below is [a shortened version of] the function used to delete computer accounts.
Is there any way I can modify the code to be able to remove Computer Accounts using the same security context (NT AUTHORITY/SYSTEM)?
private void DeleteComputerAccount(string CompName, DirectoryEntry DirEntry)
{
try
{
//Delete computer account
DirectorySearcher search = new DirectorySearcher(DirEntry, "(name=" + CompName + ")");
SearchResult res = search.FindOne();
res.GetDirectoryEntry().DeleteTree();
}
catch (Exception)
{
Throw();
}
}
Where DeleteComputerAccount is called:
DirectoryEntry dirEntry = new DirectoryEntry("LDAP://domain.contoso.com");
string compName = "MyWorkstation01";
DeleteComputerAccount(compName, dirEntry);
When a service runs as local system, it will access the network (and thus AD) in the security context of the host's computer account. You can delegate the computer account (or better, a group which the computer is a member of) the ability to delete objects from AD. This link has accurate advice on how to complete that task - http://sigkillit.com/2013/06/12/delegate-adddelete-computer-objects-in-ad/
While not what you asked, a couple other things stand out to me:
You're not filtering your search very well. You might get something other than what you want back. I'd suggest a filter like this instead: (&(objectClass=computer)(sAMAccountName=<PCName>$))
Local system is a lot of access. Could you run this as network service instead?

Impersonation to install application c#

I am trying to install windows update patch(patch.msu) in a non admin account using impersonation class provided here http://stackoverflow.com/questions/125341/how-do-you-do-impersonation-in-net
I am hardcoding the username,passowrd and domain of that of Administrator .
I tried several LogonTypes but no impact and i get the following error/exception.
"Either a required impersonation level was not provided, or the provided impersonation" .
I have no clue how to proceed further ,we need to install certain patches on our customer systems with out sharing admin details to them.
Your guidance on this is highly appreciated.
My code sample
try
{
using (Impersonation impersonate = new Impersonation(Environment.UserDomainName,
"administrator", "XXXXXX"))
{
Process proc = new Process();
proc.StartInfo.FileName = "wusa.exe";
proc.StartInfo.Arguments = strPath;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Verb = "runas";
proc.Start();
proc.WaitForExit();
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
This is due to a security update long ago.
The "Impersonate a client after authentication" and "Create global objects" user rights were first introduced in Windows 2000 Service Pack 4 to help to increase security in Windows.
Overview of the "Impersonate a Client After Authentication" and the "Create Global Objects" Security Settings (821546.KB.EN-US.2.2)
When you assign the "Impersonate a client after authentication" user right to a user, you permit programs that run on behalf of that user to impersonate a client. This security setting helps to prevent unauthorized servers from impersonating clients that connect to it through methods such as remote procedure calls (RPC) or named pipes.
As you want to impersonate an domain administrator you need to add those user rights.
By default, members of the device's local Administrators group and the device's local Service account are assigned the "Impersonate a client after authentication" user right.
Solution
IMPORTANT: This does not give full administrator permissions to the user to install other applications.
The action for the first step is dependent on the environment:
If you are using Active Directory Group Policies edit the Domain Security Policy on the Domain Controller:
Click Start -> Programs -> Administrative Tools -> Domain Security Policy
If you are not using Active Directory Group Policies, change the configuration on the local computer
Click Start -> Settings -> Control Panel -> Administrative Tools -> Local Security Policies
Then
Expand Local Policies and select User Rights Assignment.
In the right pane, double-click Impersonate a client after authentication.
In the Security Policy Setting dialog box, click Add User or Group.
In the Select Users, Computers or Groups dialog box, type the name of the Group or User who will run the application.
Select Check Names and verify the name is correct.
Repeat the steps applied to the Impersonate a client after authentication setting to the Create global objects setting.

Remote monitor directory via FileSystemWatcher [duplicate]

Suppose some Windows service uses code that wants mapped network drives and no UNC paths. How can I make the drive mapping available to the service's session when the service is started? Logging in as the service user and creating a persistent mapping will not establish the mapping in the context of the actual service.
Use this at your own risk. (I have tested it on XP and Server 2008 x64 R2)
For this hack you will need SysinternalsSuite by Mark Russinovich:
Step one:
Open an elevated cmd.exe prompt (Run as administrator)
Step two:
Elevate again to root using PSExec.exe:
Navigate to the folder containing SysinternalsSuite and execute the following command
psexec -i -s cmd.exe
you are now inside of a prompt that is nt authority\system and you can prove this by typing whoami. The -i is needed because drive mappings need to interact with the user
Step Three:
Create the persistent mapped drive as the SYSTEM account with the following command
net use z: \\servername\sharedfolder /persistent:yes
It's that easy!
WARNING: You can only remove this mapping the same way you created it, from the SYSTEM account. If you need to remove it, follow steps 1 and 2 but change the command on step 3 to net use z: /delete.
NOTE: The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as "Disconnected Network Drive (Z:)". Do not let the name fool you. It may claim to be disconnected but it will work for everyone. That's how you can tell this hack is not supported by M$.
I found a solution that is similar to the one with psexec but works without additional tools and survives a reboot.
Just add a sheduled task, insert "system" in the "run as" field and point the task to a batch file with the simple command
net use z: \servername\sharedfolder /persistent:yes
Then select "run at system startup" (or similar, I do not have an English version) and you are done.
You'll either need to modify the service, or wrap it inside a helper process: apart from session/drive access issues, persistent drive mappings are only restored on an interactive logon, which services typically don't perform.
The helper process approach can be pretty simple: just create a new service that maps the drive and starts the 'real' service. The only things that are not entirely trivial about this are:
The helper service will need to pass on all appropriate SCM commands (start/stop, etc.) to the real service. If the real service accepts custom SCM commands, remember to pass those on as well (I don't expect a service that considers UNC paths exotic to use such commands, though...)
Things may get a bit tricky credential-wise. If the real service runs under a normal user account, you can run the helper service under that account as well, and all should be OK as long as the account has appropriate access to the network share. If the real service will only work when run as LOCALSYSTEM or somesuch, things get more interesting, as it either won't be able to 'see' the network drive at all, or require some credential juggling to get things to work.
A better way would be to use a symbolic link using mklink.exe. You can just create a link in the file system that any app can use. See http://en.wikipedia.org/wiki/NTFS_symbolic_link.
There is a good answer here:
https://superuser.com/a/651015/299678
I.e. You can use a symbolic link, e.g.
mklink /D C:\myLink \\127.0.0.1\c$
You could us the 'net use' command:
var p = System.Diagnostics.Process.Start("net.exe", "use K: \\\\Server\\path");
var isCompleted = p.WaitForExit(5000);
If that does not work in a service, try the Winapi and PInvoke WNetAddConnection2
Edit: Obviously I misunderstood you - you can not change the sourcecode of the service, right? In that case I would follow the suggestion by mdb, but with a little twist: Create your own service (lets call it mapping service) that maps the drive and add this mapping service to the dependencies for the first (the actual working) service. That way the working service will not start before the mapping service has started (and mapped the drive).
ForcePush,
NOTE: The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as "Disconnected Network Drive (Z:)". Do not let the name fool you. It may claim to be disconnected but it will work for everyone. That's how you can tell this hack is not supported by M$...
It all depends on the share permissions. If you have Everyone in the share permissions, this mapped drive will be accessible by other users. But if you have only some particular user whose credentials you used in your batch script and this batch script was added to the Startup scripts, only System account will have access to that share not even Administrator.
So if you use, for example, a scheduled ntbackuo job, System account must be used in 'Run as'.
If your service's 'Log on as: Local System account' it should work.
What I did, I didn't map any drive letter in my startup script, just used net use \\\server\share ... and used UNC path in my scheduled jobs. Added a logon script (or just add a batch file to the startup folder) with the mapping to the same share with some drive letter: net use Z: \\\... with the same credentials. Now the logged user can see and access that mapped drive. There are 2 connections to the same share. In this case the user doesn't see that annoying "Disconnected network drive ...". But if you really need access to that share by the drive letter not just UNC, map that share with the different drive letters, e.g. Y for System and Z for users.
Found a way to grant Windows Service access to Network Drive.
Take Windows Server 2012 with NFS Disk for example:
Step 1: Write a Batch File to Mount.
Write a batch file, ex: C:\mount_nfs.bat
echo %time% >> c:\mount_nfs_log.txt
net use Z: \\{your ip}\{netdisk folder}\ >> C:\mount_nfs_log.txt 2>&1
Step 2: Mount Disk as NT AUTHORITY/SYSTEM.
Open "Task Scheduler", create a new task:
Run as "SYSTEM", at "System Startup".
Create action: Run "C:\mount_nfs.bat".
After these two simple steps, my Windows ActiveMQ Service run under "Local System" priviledge, perform perfectly without login.
The reason why you are able to access the drive in when you normally run the executable from command prompt is that when u are executing it as normal exe you are running that application in the User account from which you have logged on . And that user has the privileges to access the network. But , when you install the executable as a service , by default if you see in the task manage it runs under 'SYSTEM' account . And you might be knowing that the 'SYSTEM' doesn't have rights to access network resources.
There can be two solutions to this problem.
To map the drive as persistent as already pointed above.
There is one more approach that can be followed. If you open the service manager by typing in the 'services.msc'you can go to your service and in the properties of your service there is a logOn tab where you can specify the account as any other account than 'System' you can either start service from your own logged on user account or through 'Network Service'. When you do this .. the service can access any network component and drive even if they are not persistent also.
To achieve this programmatically you can look into 'CreateService' function at
http://msdn.microsoft.com/en-us/library/ms682450(v=vs.85).aspx and can set the parameter 'lpServiceStartName ' to 'NT AUTHORITY\NetworkService'. This will start your service under 'Network Service' account and then you are done.
You can also try by making the service as interactive by specifying SERVICE_INTERACTIVE_PROCESS in the servicetype parameter flag of your CreateService() function but this will be limited only till XP as Vista and 7 donot support this feature.
Hope the solutions help you.. Let me know if this worked for you .
I find a very simple method: using command "New-SmbGlobalMapping" of powershell, which will mount drive globally:
$User = "usernmae"
$PWord = ConvertTo-SecureString -String "password" -AsPlainText -Force
$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
New-SmbGlobalMapping -RemotePath \\192.168.88.11\shares -Credential $creds -LocalPath S:
You wan't to either change the user that the Service runs under from "System" or find a sneaky way to run your mapping as System.
The funny thing is that this is possible by using the "at" command, simply schedule your drive mapping one minute into the future and it will be run under the System account making the drive visible to your service.
I can't comment yet (working on reputation) but created an account just to answer #Tech Jerk #spankmaster79 (nice name lol) and #NMC issues they reported in reply to the "I found a solution that is similar to the one with psexec but works without additional tools and survives a reboot." post #Larry had made.
The solution to this is to just browse to that folder from within the logged in account, ie:
\\servername\share
and let it prompt to login, and enter the same credentials you used for the UNC in psexec. After that it starts working. In my case, I think this is because the server with the service isn't a member of the same domain as the server I'm mapping to. I'm thinking if the UNC and the scheduled task both refer to the IP instead of hostname
\\123.456.789.012\share
it may avoid the problem altogether.
If I ever get enough rep points on here i'll add this as a reply instead.
Instead of relying on a persistent drive, you could set the script to map/unmap the drive each time you use it:
net use Q: \\share.domain.com\share
forfiles /p Q:\myfolder /s /m *.txt /d -0 /c "cmd /c del #path"
net use Q: /delete
This works for me.

Windows service Problem When Accessing Remote Machine File

I created a Windows Service which Access File from Remote Machine. but It gives error in Log file that File Does Not Exist.When i deployed it then and then only it gives error otherwise when i am debugging from Visual Studio 2005 then it is working fine.
I tried to change Properties of Service from Log On tab. gives Logon as: then choose this Account and Gives Name of Remote Machine and Password Still it is not working. Please Help me out.
Code:
if (File.Exists(FileName))
{
}
else
{
Log.append("File Not Exist Path=:" + FileName, 75);
}
Error:
File Not Exist Path=: \Computer-01\Trend Till_04Feb\Trend Till_04Feb\TREND\128.DBF
I assume you are using ServiceProcessInstaller and ServiceInstaller.
The most important property is Account within the ServiceProcessInstaller class. It specifies the Windows account under which the service runs (security context). The following options are available:
LocalService: Service presents the computer's credentials to remote servers.
LocalSystem: Service presents anonymous credentials to remote servers.
NetworkService: Service has limited local privileges and presents the computer's credentials to remote servers.
User: A local or network account is specified. You may specify the necessary username and password via properties, or you may type them during installation. The Service uses the security context of the specified user account.
Following three options are provided to specify how your service is started.
Manual :- The user starts the service.
Automatic :- The service starts automatically when the system starts.
Disabled :- The service is not available for use.
Go to Properties of ServiceInstaller object and set ServiceName and StartType to Automatic.
Go to Properties of ServiceProcessInstaller and set Account property to LocalService. This causes the service to run on local service account.
HTH

Categories