Access Remote MSMQ Count - c#

My machine is in Domain D1 and there are public MSMQs in a remote server in domain D2. I am connected through vpn to D2, i.e I can RDP the machine in D2 and access the MSMQ.
What I want is to access (Know the message count) of the MSMQ without RDPing the system. So I build an application for this. I used Impersonation to impersonate the user of D2(i.e used credentials of D2)but the problem is I am not able to access the "Public" MSMQ ( used Messagequeue.GetPublicQueue() ) and exceptions are thrown with message "A workgroup installation computer does not support the operation." but when I used MessageQueue.GetPrivateQueue() it returned a collection of private queue.
I tried using MSMQManager for messageCount
Path = #"Direct:OS:machine\publicqueue";
FormatName=null;
new MSMQManager.inIt(machineName, path , FormatName);
This also throws an exception either the queue is not present or not open. but I can check that queue is working fine.

Are you comfortable doing a tiny bit of programming? If not, are you comfortable using PowerShell?
Either way - I would check out this post as it seems to contain the answers you are looking for.
Good luck, hope this helps

Your problem might be that you are working remotely.
The method GetPublicQueuesByMachine() is indeed not available over remote access.
You can see this in a feature matrix in the MSDN documentation: MessageQueue.GetPublicQueuesByMachine:
The following table shows whether this method is available in various Workgroup modes.
Workgroup mode Available
-------------- ---------
Local computer No
Local computer and direct format name No
Remote computer No
Remote computer and direct format name No
Also check the access privileges of your queues.
If I am wrong in the previous suggestion, it might be as simple as experimenting with the access rights for specific users in the network.
MSDN article Public and private queues states:
Default security access for public queues gives everyone permission to
send messages to a public queue. Specific permissions must be
granted for read access.
As for the actual message counting, John Opincar wrote a nice article about counting messages here: Counting Messages in an MSMQ MessageQueue from C#

Related

Authenticating RPC Server with NTLM

I am currently trying to improve an RPC Server I'm responsible for, both server and client run on the same machine locally, however I would like to restrict the server so that it only allows administrator (including built in /LocalSystem account) to connect to the rpc server through a named pipe.
First of all I am using the following library as a wrapper for the RPCserverApi/RPCClientApi:
https://github.com/csharptest/CSharpTest.Net.RpcLibrary
I create the Server like so:
server = new RpcServerApi(IId, MaxCalls, ushort.MaxValue, true);
server.AddProtocol(RpcProtseq.ncacn_np, Id, MaxCalls);
// Set authentication
server.AddAuthentication(RpcAuthentication.RPC_C_AUTHN_WINNT);
However when I check the named pipes security it still shows like it's not restricted at all, and my client can still connect even though I have yet to change that to specify authentication.
In addition I can check the access to that named pipe and I get:
\\.\pipe\myNamedPipe
RW Everyone
RW NT AUTHORITY\ANONYMOUS LOGON
RW BUILTIN\Administrators
Okay, So for anyone else that ran into this problem There's a few things I needed to do which was not exposed in the library I was using. So instead I created my own wrapper.
When Registering the Rpc Interface with RpcServerRegisterIf2() I had to pass through the flag:
RPC_IF_ALLOW_SECURE_ONLY
Then In addition when setting up the protocols for the RpcServer: RpcServerUseProtseqEp() I also had to pass through an SDDL, to describe the restrictions on the end point. You can find a description of SDDL's here:
https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language
To do this I created an Ace String, then used ConvertStringSecurityDescriptorToSecurityDescriptor() to create the correct object. This then locked down the end point like:
\\.\pipe\myNamedPipe
RW BUILTIN\Administrators
But also it enforced on the server that only authenticated accounts could reach it
My issue originally reported was full of misunderstandings about RPC Servers and Named pipes, I thoroughly recommend reading and understanding the following articles, as they were very helpful to me.
https://csandker.io/2021/01/10/Offensive-Windows-IPC-1-NamedPipes.html
https://csandker.io/2021/02/21/Offensive-Windows-IPC-2-RPC.html

Port requirements for System.DirectoryServices.ActiveDirectory

We have a product which implements role based authentication using AD.
At the start of this application, it tries to enumerate through all the domains in the current forest to fetch some information which will be used later.
A snippet of the code is shown below
Domain currentDomain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain));
Forest currentForest = currentDomain.Forest;
string forestName = currentForest.Name;
foreach (Domain domain in currentForest.Domains)
{
//processing code.
}
The above code runs fine until 3rd statement and the forestName variable is initialized properly with the current forest name.
But it fails in the foreach loop when it tries to execute currentForest.Domains
We are getting an ActiveDirectoryServerDownException with the error message "The specified domain either does not exist or could not be contacted" with an error code 1355.
From the below link, I got to know that this could be a dns misconfiguration or the ports might be blocked by firewall.
https://social.technet.microsoft.com/Forums/msonline/en-US/53804e9d-ccdd-450a-967b-b7e8f67cddae/active-directory-error-code-1355?forum=winserverDS
I am trying to understand the ports that need to be open for communication on server machine(Active directory server) and client machine.
The below link specifies so many number of ports which confused me.
https://support.microsoft.com/en-us/help/832017/service-overview-and-network-port-requirements-for-windows
Can some one provide me information on what are the ports that are required to be open on server and client machines so that I can successfully enumerate all the domains in the forest.
Those methods use the LDAP protocol to talk to AD, which is all over port 389.
Just to be sure, I ran your code and watched the network connections it used, and it only used port 389.
As a side note, you can simplify your code a little by using Forest.GetCurrentForest() instead of looking up the current domain then looking up the forest for that domain.
Forest currentForest = Forest.GetCurrentForest();
Either way will get the same job done.

Why does System.IO.FileSystemWatcher crash my service when I try to monitor a folder in a network share? [duplicate]

I am trying to run a file watcher over some server path using windows service.
I am using my windows login credential to run the service, and am able to access this "someServerPath" from my login.
But when I do that from the FileSystemWatcher it throws:
The directory name \someServerPath is invalid" exception.
var fileWatcher = new FileSystemWatcher(GetServerPath())
{
NotifyFilter=(NotifyFilters.LastWrite|NotifyFilters.FileName),
EnableRaisingEvents=true,
IncludeSubdirectories=true
};
public static string GetServerPath()
{
return string.Format(#"\\{0}", FileServer1);
}
Can anyone please help me with this?
I have projects using the FileSystemWatcher object monitoring UNC paths without any issues.
My guess from looking at your code example may be that you are pointing the watcher at the root share of the server (//servername/) which may not be a valid file system share? I know it returns things like printers, scheduled tasks, etc. in windows explorer.
Try pointing the watcher to a share beneath the root - something like //servername/c$/ would be a good test example if you have remote administrative rights on the server.
With regards to the updated question, I agree that you probably need to specify a valid share, rather than just the remote server name.
[Update] Fixed previous question about the exception with this:
specify the name as #"\\someServerPath"
The \ is being escaped as a single \
When you prefix the string with an # symbol, it doesn't process the escape sequences.
I was just asked this question in regards to FileSystemWatcher code running as a service and the issue is permissions. I searched and found this question and answer but unfortunately none of the answers here solved the problem. Anyway, I just solved it, so I thought I would throw in the solution here for next guy who searches and find this question.
The drive was mapped as a logged in user but the service was running as LocalSystem. LocalSystem is a different account and does not have access to drives mapped by a user.
The fix is to either:
Authenticate first (I use a C# Class to establish a network connection with credentials)
Run your service as a user that has access to the share.
You can test LocalSystem authentication by using a LocalSystem command prompt, see How to open a command prompt running as Local System?
Even though this is already answered I thought I would put in my two cents worth becaus eyou can see this same error even if you supply valid paths.
You will get the same error when the process running the watcher does not have access to the remote share. This will happen if the watcher is in a service running under the System account and the share is created by a user. System does not have access to that share and wont recognize it, you will need to impersonate the user to get access to it.
although you can use a FileWatcher over the network, you will have to account for other factors, like disconnection of the network share. If your connection to the share is terminated (maintenance, lag, equipment reset, etc) you will no longer have a valid handle on the share in your filewatcher
You can't use directory watches over network shares, this is a limitation of the OS, not of .NET.

How can you read the count of an MSMQ on another machine?

My program is successfully using .NET's MessageQueue class to read from an MSMQ. The queue is user configurable, and is sometimes on the local machine, and sometimes on a remote machine. The user can specify the remote machine either by name or IP address, and the queue name (and I'm only using "Private" queues).
I want to display to the user how many messages remain in the Queue, but haven't found a way to do this. The MessageQueue class does not seem to have a Count (or similar) property to give this to me easily.
I've been able to use the PerformanceCounter and PerformanceCounterCategory classes to get the count - but this only seems to work for me on the local machine (although I'm not completely sure I'm using these classes correctly).
My question is how to read the Count (number of messages) from an MSMQ on a remote machine?
I use the following method for message counting (works for both local and remote queues),
var machineName = "mymachine01";
var formatName = "FormatName:DIRECT=OS:mymachine01\private$\ftpreceived":
try
{
var msmqManagement = new MSMQ.MSMQManagement();
msmqManagement.Init(machineName, null, formatName );
return (uint)msmqManagement.MessageCount;
}
catch (COMException ex)
{
// If queue is not active or does not exist.
if (ex.ErrorCode == -1072824316)
{
return 0;
}
throw;
}
Note: It returns 0 in the case the queue does not exist or is not active as the MSMQ Managment API considers this the same error.
Note: If the machine name value is null it will look at the queue on the local machine.
Note: If the machinename variable is different from the machinename part of the formatname, it will return a count of messages in the "Outgoing" message queue with the given format name on the machine specified by machinename.
Active means it has 1 or more messages in it, or it has had a message in it within the last N (Not sure how big N is :)) seconds, after that time the queue is considered inactive.
The most reliable solution for getting the count of messages in a local queue is to use the MSMQ APIs using P/Invoke. There's a nice article here: Counting the number of messages in a Message Queue in .NET.
I don't know if it works with remote queues, but I wouldn't rely on it. Generally, the only thing you should do with a remote queue is to send a message. Trying to read messages or properties from a remote queue should be avoided, if possible. "Send remote and read local" will always give you the best performance and avoid all kinds of problems (e.g., what if the remote machine isn't available?)
I am using WMI to get this information. The following is an example of the code that I am using to accomplish this.
var query = String.Format("select MessagesinQueue from Win32_PerfRawdata_MSMQ_MSMQQueue where name ='{0}'", path.Replace("\\", "\\\\"));
var selectQuery = new SelectQuery(query);
using (var searcher = new ManagementObjectSearcher(selectQuery))
using (var results = searcher.Get())
{
foreach (var result in results)
{
var messages = result["MessagesinQueue"].ToString();
return long.Parse(messages);
}
}
This may be a solution for you: http://jopinblog.wordpress.com/2008/03/12/counting-messages-in-an-msmq-messagequeue-from-c/
This might be overkill, but you could possibly put a WCF service on the same machine hosting your queue, so you'd be able to retrieve the count using the performance counters in the WCF service and expose that functionality through a method of that service.
I would like to say several things here.
Before I get to my own answer, I would like to comment John Opncar's solution (in Dr. Wily's Apprentice answer). His code does work on remote machines. I used his code in our project at work to watch the queues on a remote cluster server and it works very well.
So, if get "RemoteMachineNotAvailable" errors, please check your configurations. Are all machines in the same network or - not to forget - are the queue's security permissions on the remote machine set up to allow others to read them?
Do the users/ accounts have sufficient rights to read from other systems?
For example, we had to allow everyone on the clustered queues.
As far as I know the PerformanceCounters do indeed have problems to read message properties on remote machines. I tried to use them for queues in a Windows Server cluster environment, but was never able to get it working. I did some internet research at that time, but unfortunatelly I do not recall if this is due to security reasons or simply a bug. :-(
Now to the actual answer. If you do not like the Cursor-Method as described by John Opincar you could also use the MessageQueue.GetAllMessages() or MessageQueue.GetMessageEnumerator methods.
I never tried GetMessageEnumerator, but I can say that I would not recommend GetAllMessages().
We suffered from heavy performance issues when using it every second on a system with several queues that contain several thousands of messages.
The method takes a snapshot of all messages in the queue, which can cause heavy loads in memory and network.
The cursor-methodis still somewhat slow. But, at least in our production environment, it feels more snappy than with the GetAllMessages() solution.
If counting the messages in your scenario does not need to be as often as one second and you have less messages to count than we do, then working with GetAllMessages() or GetMessageEnumerator() might be a possible solution for you.
Finally, it always comes down to your own individual needs.

FileSystemWatcher Fails to access network drive

I am trying to run a file watcher over some server path using windows service.
I am using my windows login credential to run the service, and am able to access this "someServerPath" from my login.
But when I do that from the FileSystemWatcher it throws:
The directory name \someServerPath is invalid" exception.
var fileWatcher = new FileSystemWatcher(GetServerPath())
{
NotifyFilter=(NotifyFilters.LastWrite|NotifyFilters.FileName),
EnableRaisingEvents=true,
IncludeSubdirectories=true
};
public static string GetServerPath()
{
return string.Format(#"\\{0}", FileServer1);
}
Can anyone please help me with this?
I have projects using the FileSystemWatcher object monitoring UNC paths without any issues.
My guess from looking at your code example may be that you are pointing the watcher at the root share of the server (//servername/) which may not be a valid file system share? I know it returns things like printers, scheduled tasks, etc. in windows explorer.
Try pointing the watcher to a share beneath the root - something like //servername/c$/ would be a good test example if you have remote administrative rights on the server.
With regards to the updated question, I agree that you probably need to specify a valid share, rather than just the remote server name.
[Update] Fixed previous question about the exception with this:
specify the name as #"\\someServerPath"
The \ is being escaped as a single \
When you prefix the string with an # symbol, it doesn't process the escape sequences.
I was just asked this question in regards to FileSystemWatcher code running as a service and the issue is permissions. I searched and found this question and answer but unfortunately none of the answers here solved the problem. Anyway, I just solved it, so I thought I would throw in the solution here for next guy who searches and find this question.
The drive was mapped as a logged in user but the service was running as LocalSystem. LocalSystem is a different account and does not have access to drives mapped by a user.
The fix is to either:
Authenticate first (I use a C# Class to establish a network connection with credentials)
Run your service as a user that has access to the share.
You can test LocalSystem authentication by using a LocalSystem command prompt, see How to open a command prompt running as Local System?
Even though this is already answered I thought I would put in my two cents worth becaus eyou can see this same error even if you supply valid paths.
You will get the same error when the process running the watcher does not have access to the remote share. This will happen if the watcher is in a service running under the System account and the share is created by a user. System does not have access to that share and wont recognize it, you will need to impersonate the user to get access to it.
although you can use a FileWatcher over the network, you will have to account for other factors, like disconnection of the network share. If your connection to the share is terminated (maintenance, lag, equipment reset, etc) you will no longer have a valid handle on the share in your filewatcher
You can't use directory watches over network shares, this is a limitation of the OS, not of .NET.

Categories