I have a process which is hosting a WCF Named Pipe server.
The process runs under a user account with no admin privileges.
When a client tries to connect to the pipe it receives a timeout exception and the server fails with the following exception:
Throwing an exception. Source: System.ServiceModel 4.0.0.0. Exception details: System.ServiceModel.AddressAccessDeniedException: Cannot listen on pipe 'net.pipe://localhost/path/to/endpoint': Access is denied. (5, 0x5) ---> System.IO.PipeException: Cannot listen on pipe 'net.pipe://localhost/path/to/endpoint': Access is denied. (5, 0x5)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.PipeConnectionListener.CreatePipe()
at System.ServiceModel.Channels.PipeConnectionListener.BeginAccept(AsyncCallback callback, Object state)
at System.ServiceModel.Channels.ConnectionAcceptor.AcceptIfNecessary(Boolean startAccepting)
After reading Chris Dickson's blog, I can think of three possible things that cause this:
Somehow, the user in not being added to the ACL
The user is not given the FILE_CREATE_PIPE_INSTANCE permission
The deny ACE for the Network Users group is denying permission
Notes:
Using a non-WCF named pipe, adding current user and the built-in administrator to the ACL works just fine.
A similar endpoint in a process running under a SYSTEM account works just fine.
When testing the code under my own user account everything works fine.
The host must remain a process and must have non-admin privileges.
I tried adding the current user and the built-in administrator to the ACL as suggested in Chris Dickson's blog but it did not help.
I tried setting NetNamedPipeSecurityMode to None but that didn't help either.
Related
We have a Windows Service that sits and monitors our main Windows Service. It can query the service status, stop, start, and restart the service as required. It does so using the ServiceController class in .Net.
When installed using our installer, the services can be configured to use an existing Windows User account, or a new account can be created for the services. This user can be an Admin or a Non-Admin user. Either way, when installed, the monitor service is configured to start Automatically and the Main service is set to Manual, and the configured user account is explicitly granted all of the required permissions to control the Main service. I have double checked the DACL and confirmed that the user does indeed have permission.
Most of the time, the two services are installed on the same machine, but it is possible that they could be on different machines, so when new'ing up the ServiceController we pass in the service name and the IP address of the machine.
The issue is, on calling ServiceController.Start() we get the following Exception:
System.InvalidOperationException: Cannot open MyServiceName service on computer '127.0.0.1'. ---> System.ComponentModel.Win32Exception: Access is denied
--- End of inner exception stack trace ---
at System.ServiceProcess.ServiceController.GetServiceHandle(Int32 desiredAccess)
at System.ServiceProcess.ServiceController.Start(String[] args)
at System.ServiceProcess.ServiceController.Start()
).
This happens only when the configured user is non-admin, using an IPv4 address, and only on Windows 10 since the 1709 update. This exception does not occur on any previous version of Windows, including all previous versions of Windows 10 (and yes, I have tested all of them, urgh).
It also seems that the exception does not happen when using the hostname of the machine or "localhost", only when using an IPv4 address such as "127.0.0.1" or the actual IP of the machine.
The issue can be reproduced using the following little console program:
using System;
using System.ServiceProcess;
namespace ServiceStartTest
{
class Program
{
static void Main(string[] args)
{
try
{
var serviceController = new ServiceController("MyServiceName", "127.0.0.1");
serviceController.Start();
}
catch (Exception ex)
{
Console.WriteLine($"Exception caught: {ex}");
}
Console.ReadLine();
}
}
}
Run as a non-administrator user and replace "MyServiceName" with the installed name of a service you can control.
I'd really like to know what changed in 1709 that caused this and if there's a way around it other than using hostnames.
We have a big system with bunch of services communicating with each other via TIBCO EMS Messaging.
Now, one of the services keeps throwing this exception when it tries to connect to EMS server:
TIBCO.EMS.IllegalStateException: connect failed: server in standby mode
However, other services on the same EMS server are working just fine without any exception.
I tried to reproduce this by creating a console application which would use same credentials to connect to EMS server on the same destination (Queue) but couldn't reproduce this error.
EMS connection is fault-tolerant and it might have been failed over to secondary server, however, now I see primary server is back up.
I also tried to connect to primary server only (which I can see is up & running) but it fails with the same exception.
Below is the stack trace for reference:
TIBCO.EMS.IllegalStateException: connect failed: server in standby mode
at TIBCO.EMS.CFImpl._CreateConnection(String userName, String password, Boolean xa)
at TIBCO.EMS.ConnectionFactory.CreateConnection(String userName, String password)
at Ems.makeConn()
We're using TIBCO.EMS.dll v. 8.1.0.10 on .NET 4.0.
Any idea what can cause this exception ?
Could your connection string only mention one of the hosts inside an FT/HA setup ? This looks like the error message returned when you are trying to connect to only one of the HA/FT host, but not the one active at the moment.
If it is the case, the connection string will work most of the time, but a proper EMS HA connection string include two (or more!) EMS host and port. Only one is active at the same time.
It typically looks like this:
serverUrl=tcp://server0:7222, tcp://server1:7344
See source doc here in TIBCO docs.
It turned out tools we were using to check if server is active (we don't have admin rights on the servers) was misbehaving (showing incorrect status), so none of those servers were really active (not primary nor secondary).
As soon as server was brought up this error message went away.
I am using the API System.DirectoryServices.AccountManagement to bind to an AD-LDS instance. I am using simple bind with a user that exists locally in the AD-LDS instance. It works when I run the client on the server that hosts AD-LDS but it doesn't work when I run the client on a remote computer.
This is the code I use to bind and search for a user:
var c = new PrincipalContext(ContextType.ApplicationDirectory, "fullhostname:50001", "CN=Users,DC=app,DC=local", ContextOptions.SimpleBind, "CN=joe,CN=Users,DC=app,DC=local", "abc");
var u = UserPrincipal.FindByIdentity(c, IdentityType.Name, "john");
This is the exception that is thrown when I run it on a remote computer:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server is not operational.
---> System.Runtime.InteropServices.COMException: The server is not operational.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectoryEntry.get_Options()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
--- End of inner exception stack trace ---
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoApplicationDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
at System.DirectoryServices.AccountManagement.PrincipalContext.get_ConnectedServer()
at MyApplication.DiagnosticsController.TryAdLdsSettings(AdLdsData data) in C:\code\MyApplication\DiagnosticsController.cs:line 166
If I instead use the System.DirectoryServices API it works also from remote computer:
var obj = new DirectoryEntry("LDAP://fullhostname:50001/CN=Users,DC=app,DC=local", "CN=joe,CN=Users,DC=app,DC=local",
"abc", AuthenticationTypes.None);
obj.RefreshCache();
This works, but I need to use System.DirectoryServices.AccountManagement API instead.
Anyone knows what is wrong?
I was able to get this to work on a domain, with a few minor changes, I hope these tips help.
Your 2nd-to-last parameter when creating PrincipalContext, "CN=joe,CN=Users,DC=app,DC=local", should be the fully qualified username, not the LDAP path; this will normally look like COMPUTER-NAME\\joe (whatever your computer is named) or if you are on a domain as I am, DOMAIN-NAME\\joe. (If fullhostname is not your local workstation, then you may be on a domain, or you may need to specify fullhostname\joe to request authentication against the host server rather than your local, since your local's credentials probably won't work on the host server).
For testing this on a Domain, I had to change the first parameter from ContextType.ApplicationDirectory to ContextType.Domain; it sounds like you are not on a domain, so you will probably need ContextType.ApplicationDirectory, but the error message makes me think that Active Directory Services aren't running.
Since :50001 is high enough to be blocked, make sure you don't have firewall software that is blocking the request, either outgoing from your machine, or incoming to the "fullhostname" machine; and, of course, make sure your active directory services are actually available on 50001, and not some other authentication protocol.
I ended up rewriting my usages of PrincipalContext and UserIdentity to use DirectoryEntry directly instead. It took me a few hours to find appropriate reimplementations for the convenient UserIdentity functions I needed, but after doing so everything worked fine.
It's quite a mystery to me why the problem occurred in the first place. My only guess is that with my particular version of AD LDS in my particular configuration, there's a bug somewhere in the underlying libraries. Rewriting everything directly in DirectoryEntry, getting everything as exactly similar as I know how to do, fixed the problem.
I have a Windows service that regulary runs a PowerShell script on a remote computer via WsManConnectionInfo/RunspaceFactory (following the steps from this article: Remotely Executing Commands in PowerShell using C#):
var connectionInfo = new WSManConnectionInfo(false, server, 5985, "/wsman",
"http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
cred)
{
OperationTimeout = 4*60*1000,
OpenTimeout = 1*60*1000
};
using (var runSpace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runSpace.Open();
using (var p = runSpace.CreatePipeline())
{
p.Commands.AddScript(script);
var output = p.Invoke();
...
}
}
Now, if I run the Windows service itself with an Administrator account, all is well. But if i run the service with the LocalSystem account, I get the following exception;
System.Management.Automation.Remoting.PSRemotingTransportException:
Connecting to remote server NOSRVDEV02 failed with the following error message :
WinRM cannot process the request. The following error with
errorcode 0x8009030d occurred while using Negotiate authentication:
A specified logon session does not exist. It may already have been terminated.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
at System.Management.Automation.Runspaces.AsyncResult.EndInvoke()
at System.Management.Automation.Runspaces.Internal.RunspacePoolInternal.EndOpen(IAsyncResult asyncResult)
at System.Management.Automation.RemoteRunspace.Open()
...
Note: This has nothing to do with the credentials in WSManConnectionInfo - just the account settings in the service properties "Log On" tab.
I don't want to give the service admin privileges. Any ideas why the LocalSystem user fails to log in?
Additional info:
The remote computer is not a member of a domain.
I have tried to connect both by IP address and hostname (both are listed in the local computer's TrustedHosts).
EDIT: Even more info (summary of the comments):
Local computer: Windows 7 Ultimate 64bit (virtual machine on a Windows 8 box).
Remote computer: Windows Server 2008R2 Datacenter 64bit.
The main reason we don't want to change service user accounts is that this is an update to an old service which is already deployed on many clients (customers).
The service also accesses the Windows registry and the file system on the local computer, so setting the user account to something more restricted, like NetworkService, would just open a different can of worms.
A rather surprising solution to this one: The username in the PSCredential object (cred) needed to be prefixed with the domain-less remote computer's name, e.g. "MYREMOTESERVERNAME\remoteusername" and not just "remoteusername".
I have no idea why the prefix is needed only when connecting with the LocalSystem account though...
I am trying to connect to a remote queue using c#.
I tried many ways to connect to the remote queue but it always fails with common errors like: MQRC_CHANNEL_CONFIG_ERROR or MQRC_HOST_NOT_AVAILABLE.
What I am doing is this:
string channel = "QM_TEST.SVRCONN";
string hostname = "<serverIp>";
string queueName = "QM_TEST";
string port = 1414;
props.Add(MQC.HOST_NAME_PROPERTY, hostname);
props.Add(MQC.CHANNEL_PROPERTY, channel);
props.Add(MQC.PORT_PROPERTY, port );
props.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
MQQueueManager mqQueue = new MQQueueManager(queueName, props);
I have tried changing this but all failed.
I think that my problem is the server configurations..
can you point me to a full guide to how to configure a server and connect to it with .net?
My problem is connecting to a REMOTE server using .net and not to a local server.
Thank you!
The problem was that the CCSID between the client and the server were different.
http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/index.jsp?topic=%2Fcom.ibm.mq.csqzaf.doc%2Fcs12480_.htm
On the client side I had to put
Environment.SetEnvironmentVariable("MQCCSID", "437");
Thats why I got:
MQRC_CHANNEL_CONFIG_ERROR
I'm guessing the problem (or at least a problem) is here:
MQQueue mqQueue = new MQQueueManager(queueName, props);
This should be
queueManager = new MQQueueManager(queueManagerName, properties);
If you have installed the WebSphere MQ client to the default location, there are many sample programs under the following directory:
C:\Program Files (x86)\IBM\WebSphere MQ\tools\dotnet\samples\cs\base\
There are a number of sample programs there for various tasks. If you have the latest V7.1 client installed then you will see the following programs:
SimpleAsyncPut
SimpleClientAutoReconnectGet
SimpleClientAutoReconnectPut
SimpleGet
SimpleMessageProperties
SimplePublish
SimplePut
SimpleReadAhead
SimpleSharingConversation
SimpleSubscribe
SimpleXAGet
SimpleXAPut
There are also WCF and XMS samples.
If you need the client code, please see my response to another SO question here for links.
Update:
Here's the normal diagnostic process.
If the WMQ components were installed by relocating libraries or classes from somewhere else, perform an install using the full vendor-supplied client media. This includes troubleshooting utilities such as trace, dspmqver, etc. It also resolves any library or class mismatch issues.
Use the pre-compiled client programs to test the connection. The amqsputc, amqsgetc and amqsbcgc programs require the MQSERVER environment variable as described here. The Q program from SupportPac MA01 is a separate download but has the advantage of NOT requiring any environment variables, CCDT files or other dependencies.
If the sample programs fail, check the QMgr's error logs at [WMQ install]/qmgrs/[QMgr name]/errors/AMQERR01.LOG for messages. Also check for FDC files and errors in [WMQ install]/errors.
If no errors on the QMgr side, attempt the connection again while using a client-side trace as described here and here.
Most client problems are resolved through installation of the full WMQ client as supplied by IBM. (Conversely that implies most people are installing by grabbing DLL or JAR files.) If the problem persists, error log inspection on the QMgr and client side usually reveals the underlying cause. If these do not work then tracing usually diagnoses the remaining issues.
UPDATE 2:
Per the error messages posted at MQSeries.net, the channel has a security exit set. A security exit is external code that the channel calls out to when starting a channel. There is no way to know what the exit expects or does without having access to the code or docs of the exit. If the exit is written in-house, you'll need to talk to the programmer to figure out what it requires. If the exit is a commercial product then you will need to get the documentation for it.
Alternatively, alter the channel so that SCYEXIT is blank to disable the exit.
The data posted at MQSeries.net was as follows:
MQ9575: DCE Security: failed to get the user's login name.
EXPLANATION:
System call 192.168.50.55 to get the login name of the user running WebSphere
MQ client application process 5 failed with error value -1. This occurred in
security exit function create_cred. The exit will now attempt to open channel
using the DCE default login context.
ACTION:
If you wish to run using the DCE default login context take no action. If you
wish to run using the user's login name as the DCE security exit principal
examine the documentation for the operating system on which you are running MQ
clients and reconfigure the operating system as necessary to allow the
192.168.50.55 call to succeed.
Note that it states the call is failing in the security exit.