Port requirements for System.DirectoryServices.ActiveDirectory - c#

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.

Related

How do I remotely access self-hosted Nancy service?

I am creating a simple Windows service that hosts a Nancy instance to provide views of its internal data. Everything works as expected when using a browser on the local machine; I see the view that it serves up. However, I cannot find any reason why it will not access from a remote browser (on the same network). Access from a remote browser simply delays a while; IE will eventually display "This page can’t be displayed;" Safari on an iPad shows the partial progress bar for a while and does nothing.
I'm binding using all local IPs, not just localhost.
I am using the GetUriParams() function at this link to discover all local IP addresses for binding. http://www.codeproject.com/Articles/694907/Embed-a-web-server-in-a-windows-service
_nancyHost = new NancyHost(GetUriParams(port));
_nancyHost.Start();
I discovered at this page that binding to localhost works for local access only. http://forums.asp.net/t/1881253.aspx?More+SelfHost+Documentation
The IPs that this function discovers are for Ethernet adapter, Wireless adapter, and two VMware Network adapters from a prior installation of a VMware player. I've tried the remote access both by machine name and by literal IP to the Ethernet adapter.
I added entries to urlacl list.
I have used the netsh http add urlacl command as recommended in many places, including at this link: Remote access to a Nancy Self Host
If I perform netsh http show urlacl, I see the entry for the port I'm using.
I tried different Nancy configs
If I set the Nancy configuration option for UrlReservations.CreateAutomatically, I will get security prompts, which after allowing, I see new entries in netsh http show urlacl list output for all of the local IPs, but it still does not allow remote access. I also tried the RewriteLocalHost option true and false.
I've tried starting Nancy with http://+:3684 or http://*:3684 (which gets parsing exception from Uri()) and with http://0.0.0.0:3684 (which gets exception from AddAllPrefixes() within HttpListener()).
I added the EXE to Windows firewall
I have created firewall exceptions as described here: https://msdn.microsoft.com/en-us/library/ms733768.aspx
The associated rule shows Private,Public and "Any" for every column with both TCP and UDP.
I tried running Nancy in different environments. I've run the code in: the Windows Service running as Local System, a console app within Visual Studio 2013 debugger, and the console app Run As Administrator.
I imagine it's a simple security setting, but I've googled and searched and tried various things for a couple of days now.
What am I missing?
This answer provided the clue I needed.
https://stackoverflow.com/a/21364604/1139376
This is because HttpListener is built on top of http.sys which will listen on the port you specified on behalf of your program.
It wasn't my EXE doing the actual listening. All I needed to do was to add an Incoming rule to the Windows Firewall set for the "System" program and the specific TCP port I'm using. That allowed remote access.
Use the HostConfiguration and let Nancy make the URL reservations automaticaly for you.
var config = new HostConfiguration
{
RewriteLocalhost = true,
UrlReservations = new UrlReservations { CreateAutomatically = true }
};
host = new NancyHost(new Uri("http://localhost:8080"), new DefaultNancyBootstrapper(), config);
host.Start();
Note that this will force ACL to create network rules for new ports if they do not already exist.

Access Remote MSMQ Count

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#

Get mac address from IP using DHCP?

I am trying to create scripts/services that allow for waking PCs in a windows domain via WOL. Now i want to give the user the option to select an AD container as a starting point for the waking of PCs contained within. My initial thought is using DHCP as a repository to query for MAC addresses given the hostnames (which i can easily enough pull from AD given the container).
Is there a way to programmatically query the DHCP service/server, passing hostnames and recover the associated MAC addresses?
Or, is there a better/easier way to solve my problem?
This is a little bit wacky it seems that there's no way to query the DHCP server programmatically. Thanks cottsak for asking the question. I understand that the DHCP protocol doesn't have such a query, but I thought mayb the executable from Microsoft might have some way you can address it from the command line. I haven't heard anybody anywhere say that there is no such case, but it must be so.
WHOA, wait a minute... I think I found what we're looking for: NETSH. cf:
http://social.technet.microsoft.com/Forums/en/ITCG/thread/afb4be16-09bd-4260-b515-8323d85d4ccb
Where it says if you open a command prompt on the DHCP server you can run this command:
netsh dhcp server scope 192.168.1.0 show clients
and get a report such as this:
10.10.98.53 - 255.255.255.0 -00-0c-29-02-a4-09 - NEVER EXPIRES -D
10.10.98.54 - 255.255.255.0 - 00-22-19-10-29-75 -1/21/2012 8:39:25 AM -D
Yippeee! Thanks for the thread!! If it wasn't for this one, I enver would have narrowed my search to technet adn found that one.
Try dhcpexim.exe from microsoft.
or, if you prefer using pure C. DhcpEnumSubnetClientsV4
No problem; because all of the machines are in your domain you can put together a VBScript that will get the MACAddress(es) from the local machine and store it as an attribute of the computer object in Active Directory.
Here's a quick hack on how to do that (save this as a .vbs-file):
Option Explicit
Const ADS_PROPERTY_UPDATE = 2
Const COMPUTERLOCATION = "ou=Member Servers,dc=yourdomain,dc=com"
Const ATTRIBUTETOUSE = "otherTelephone"
Dim wshNetwork, strComputerName
Set wshNetwork = WScript.CreateObject("WScript.Network")
strComputerName = wshNetwork.ComputerName
Dim objWMIService, colNetCards, objComputer, objNetCard
Set objWMIService = GetObject("winmgmts:\\" & strComputerName & "\root\cimv2")
Set colNetCards = objWMIService.ExecQuery("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled = True")
Set objComputer = GetObject("LDAP://cn=" & strComputerName & "," & COMPUTERLOCATION)
For Each objNetCard in colNetCards
objComputer.PutEx ADS_PROPERTY_APPEND, ATTRIBUTETOUSE, Array(objNetCard.MACAddress)
objComputer.SetInfo
Next
Because your clients aren't all in the "Member Servers" OU above you'll need to modify the above script to include a directory search for the strComputerName do get the COMPUTERLOCATION.
When you have a working script, ask your domain administrator to put the script as a start-up script targetting the computers you need to monitor; that way it'll execute whenever a computer boots up. You can also run the script as a scheduled task to get your data from any clients that haven't rebooted or use psexec or some other way you can think of to get the data immediately. Or you can rewrite the script entirely to remote connect to all of your machines and get the data that way (which might not be possible due to local firewalls). Or you could write a small .NET console application which does the same thing, it's up to you...
Also, although there is a networkAddress-attribute defined for computer objects; by default the computer object itself does not have access to write to this property. Because start up-scripts run in the context of the SYSTEM account on the particular machine the easiest thing is to use an attribute that the computer object (SELF) has write access to. The otherTelephone-attribute is multivalued and part of the Personal-Information Property Set which all computer objects has write access to by default. If you want to use the networkAddress-attribute you need to set explicit write access to that attribute for all of your computers.
Also you need to bear in mind that storing the the MAC address in Active Directory means that all of the users in your domain will have read access to it which in turn might possibly (depending on your environment) pose a small security risk.
To do it the way the network does.
Grab SharpPcap (Pcap wrapper for C#) and WinPcap (Windows) or libpcap (*nix). Write an application that creates SNMP packets to query the ARP table on the router.
Note: The ARP (Address Resolution Protocol) table is the table containing the mapping of IP address to MAC address.
I've been thinking about implementing an example that does this lately but I don't have one to show yet. Once I do, I'll make sure it gets added to the SharpPcap examples found in the project's source tree.
You can't do that with DHCP. DHCP attributes IP from MAC, not the other way around.
ARP is what converts IP into MAC but it's the machine itself that answers ARP requests so if it's off it's obviously not gonna answer ...
I suggest you store the MAC in your AD directly (I guess AD supports custom attributes ?)
you need to use arp to get a mac adress and doing so In C is a long process.
Mac adresses are hard coded, so if you have X computers go and get X mac addresses and tie them to the AD.
Note that the computer will have to be on to request its mac address.
Finding MAC address from IP address
Yeah dun worry about it, you can pull this info directly from DHCP if the PC has a lease.
Know how you right click and add a reservation in DHCP?
Look in DHCP for the 'unique ID'. It's the MAC address, sans the colons.

problem connecting to Active Directory server in C# .NET

I'm currently writing some software in C# which needs to connect to an AD server and get some user details. When I connect using the code below it works against most AD servers that I connect to but there are a couple where it fails with an error of "Logon failure: unknown user name or bad password.". The server name / credentials I'm using are definately correct as I've tested them with an LDAP Browser and the AD server is using standard security (port 389 etc). Can anyone offer any advice?
Cheers
Tim
DirectoryEntry d = new DirectoryEntry("LDAP://" + domain, admin_username, admin_password);
try
{
object x = d.NativeObject;
}
catch
{
throw;
}
I've had similar issues programming .net / AD in the past. One thing I found useful is using an LDAP viewer to see if I can connect to certain servers, etc. In this way, I can at least determine if it is a .NET error (perhaps my code), a credential error, etc.
I use the free/lite version of Softerra's LDAP viewer (http://www.ldapbrowser.com/download.htm) although I'm sure there are many others to choose from out there. If you try the one listed here, make sure to download the 'LDAP browser' and not 'LDAP Administrator'. The browser is the free one.
Try connecting to the same LDAP path you're having trouble with in code, using a LDAP browser/viewer. This will at least as step one determine if it is a .NET/code issue or not. If you can't connect via the browser, it can be helpful to play around with the connection options, such as port, domain (FQDN), etc.
Hope this might help narrow things down.
Active Directory allows at least three different logon name styles:
LDAP - i.e. LDAP DN. For example: cn=JohnS, ou=Users, dc=example, dc=com
NTLM. For example: EXAMPLE\JohnS
Kerberos principal name: For example: johns#example.com
However, you cannot login with just JohnS like you do with Windows box. It's a very common mistake.

How should I validate a user's credentials against an ADAM instance over SSL?

Apologies in advance as I haven't had much experience with directories before.
I have an ASP.net application, and I have to validate its users against an Active Directory Application Mode instance running on Server 2k3. I was previously attempting a connection with DirectoryEntry and catching the COMException if the user's credentials (userPrincipalName & password) were wrong, but I had a number of problems when trying to bind as users who weren't a member of any ADAM groups (which is a requirement).
I recently found the System.DirectoryServices.AccountManagement library, which seems a lot more promising, but although it works on my local machine, I'm having some troubles when testing this in our testbed environment. Chances are I'm simply misunderstanding how to use these objects correctly, as I wasn't able to find any great documentation on the matter. Currently I am creating a PrincipalContext with a Windows username and password, then calling the AuthenticateCredentials with the user's userPrincipalName and password. Here's a very short exert of what I'm doing:
using (var serviceContext = new PrincipalContext(
ContextType.ApplicationDirectory,
serverAddress,
rootContainer,
ContextOptions.Negotiate | ContextOptions.SecureSocketLayer,
serviceAccountUsername,
serviceAccountPassword)) {
bool credentialsValid = serviceContext.ValidateCredentials(userID, password, ContextOptions.SecureSocketLayer | ContextOptions.SimpleBind)
}
If the user's credentials are valid, I then go on to perform other operations with that principal context. As I said, this works for both users with and without roles in my own environment, but not in our testbed environment. My old DirectoryEntry way of checking the user's credentials still works with the same configuration.
After a very long morning, I was able to figure out the problem!
The exception message I was receiving when calling ValidateCredentials was extremely vague. After installing Visual Studio 2008 in the test environment (which is on the other side of the country, mind you!), I was able to debug and retrieve the HRESULT of the error. After some very deep searching in to Google, I found some very vague comments about "SSL Warnings" being picked up as other exceptions, and that enabling "SCHANNEL logging" (which I'm very unfamiliar with!) might reveal some more insight. So, after switching that on in the registry and retrying the connection, I was presented with this:
The certificate received from the remote server does not contain the expected name. It is therefore not possible to determine whether we are connecting to the correct server. The server name we were expecting is ADAMServer. The SSL connection request has failed. The attached data contains the server certificate.
I found this rather strange, as the old method of connecting via SSL worked fine. In any case, my co-worker was able to spot the problem - the name on the SSL certificate that had been issued on the server was that of the DNS name ("adam2.net") and not the host name ("adamserver"). Although I'm told that's the norm, it just wasn't resolving the correct name when using PrincipalContext.
Long story short; re-issuing a certificate with the computer name and not the DNS name fixed the problem!

Categories