none
Querying Domains/Users On Newer Operating Systems Without the Computer Browser Service... RRS feed

  • Question

  • Hi there,

    I have a problem that I hope there is a code solution for.  We use InstallShield to package our applications for deployment and part of our installations uses their out of the box Logon Dialogs (to enter a user name and password).  The problem is that these dialogs rely on the Computer Browser, which in turn relies on SMB 1.0.  Apparently the SMB feature has some security drawbacks so it is not enabled by default on newer OSs.

    I have made InstallShield aware of this issue and they entered it as an enhancement request.

    Anyway, I would like to rework those dialogs which worked as follows (if all network requirements are in place)..  Click a domain browse button, which would display a list of available domains and machines.  After that is selected there is a browse to select a user.  A password is then entered and the information is validated when the Next button is clicked on the main dialog.

    What I would like to do is hopefully rely on a different, coded method to first simply verify the manually entered domain\usernam, password.  I could possibly phase domain and user lists in later.  However, I'm hoping there is another way to verify a user without relying on the Computer browser service or some other, older prerequisite.

    I have some code cobbled together that will verify a user on the domain I am working under, but can't see or validate other domain users.  Then I thought there was a trust issue, maybe so I cobbled something else together to hopefully check trust relationships, but that only displays the name of the domain I'm currently working from.

    The thing about Trust Relationships is that I can see everything from the InstallShield dialogs when all the prerequisite pieces are in place.

    I'm sure there is a lot more I'm not explaining properly, but I just need to verify entered credentials...  Domain1\My.User while running things (install or code) on a machine in Domain2.  Is that possible and what has to be in place before any code can work?

    Please fire questions about holes in my store and I will try to answer them the best I can.


    Thank You

    Wednesday, February 19, 2020 6:47 PM

All replies

  • While I cannot verify whether Computer Browser or SMB 1.0 is required, to validate a user's credentials you can use P/Invoke to call the underlying LogonUser API. Alternatively use PrincipalContext.ValidateCredentials. If a domain is specified then create the PrincipalContext for that domain and then validate. 

    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, February 19, 2020 9:43 PM
    Moderator
  • Wow, creating the PrincipalContext for the supplied domain and then validating seems to work.  I uninstalled SMB1 from the test system, which seems to remove the Computer Browser service.  I'm able to verify user from two different domains on this machine.

    So, with this I think I can accomplish phase one of my installation dialog change, which would be to verify domain\user; password manually entered by the user before continuing.  If they make any type of typo, the validation will fail and the install will not continue unless and until the entry(ies) are corrected.

    Following phases would involve querying availabe or reachable domains for selection from a list.  After selection, show available users in that domain.  I don't know it that will be easily doable or not.


    Thank You

    Tuesday, March 3, 2020 1:28 PM
  • Hi SuperFreak31,

    If you want to get all domains, you can add a reference: System.DirectoryServices.dll, and then use the following code to get it.

    public static ArrayList EnumerateDomains()
    {
        ArrayList alDomains = new ArrayList();
        Forest currentForest = Forest.GetCurrentForest();
        DomainCollection myDomains = currentForest.Domains;
    
        foreach (Domain objDomain in myDomains)
        {
            alDomains.Add(objDomain.Name);
        }
        return alDomains;
    }

    As for getting users, you can try this code example.

    DirectoryEntry entry = new DirectoryEntry("LDAP://" + Bous.DomainName, Bous.UserName, Bous.Password);
    DirectorySearcher mySearcher = new DirectorySearcher(entry);
    mySearcher.PageSize = 1000;   // <--- Important!
    mySearcher.Filter = ("(&(objectCategory=person)(objectClass=user))");
    
    foreach (SearchResult result in mySearcher.FindAll())
    {
         dr = dt.NewRow();
         ResultPropertyCollection myResultPropColl = result.Properties;
         dr[0] = myResultPropColl["samaccountname"][0].ToString() + "@" + Bous.DomainName;
         dt.Rows.Add(dr);
    }  

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, March 4, 2020 6:14 AM
  • Thank Timon!  I did try similar domains acquisition code a while back, but I couldn't get all domains or at least the ones I was expecting.  Then I thought maybe there were trust levels that need to be accounted for so I was trying code around that as well.

    Using the code below I was able to see the domain on a machine in a particular domain, but not the other domain.  For example, on a machine in the domain1 domain, if I run the code, I only see that domain.

    If I'm on a machine in domain2, I can only see domain2 through this code.  I was hoping that I would see both from either machine.  When I couldn't I thought about trust levels.  Even with code to supposedly deal with that, I still can't see across domains.

    Again, the purpose of all of this is to sidestep some out of the box InstallShield dialogs as they are based on some older technologies, Computer Browser service, which in turn is reliant upon SMB1, which is basically deprecated due to security issues.

    Here's the code I was using to simply display each domain encountered in a message box...

    private void Button1_Click(object sender, EventArgs e)
    {
        using (var forest = Forest.GetCurrentForest())
        {
            foreach (Domain domain in forest.Domains)
            {
                MessageBox.Show(domain.Name);
                domain.Dispose();
            }
        }
    }

    Here's code related to my trust tries...

    private void Button3_Click(object sender, EventArgs e)
            {
                Forest forest = Forest.GetCurrentForest();
    
                MessageBox.Show(forest.Name);
    
                //MessageBox.Show(forest.GetAllTrustRelationships().Count.ToString());
    
                foreach (TrustRelationshipInformation trust in forest.GetAllTrustRelationships())
                {
                    if ((trust.TrustDirection == TrustDirection.Bidirectional) || (trust.TrustDirection == TrustDirection.Outbound))
                    {
                        MessageBox.Show(trust.TargetName);
                        TestDomain(trust.TargetName);
    
                        if (trust.TrustType == TrustType.Forest)
                        {
                            DirectoryContext rootDomainContext;
                            Domain rootDomain;
                            TrustRelationshipInformationCollection domainTrusts;
    
                            rootDomainContext = new DirectoryContext(DirectoryContextType.Domain, trust.TargetName);
                            rootDomain = Domain.GetDomain(rootDomainContext);
                            domainTrusts = rootDomain.GetAllTrustRelationships();
    
                            foreach (TrustRelationshipInformation domainTrust in domainTrusts)
                            {
                                if ((domainTrust.TrustType == TrustType.ParentChild) && ((domainTrust.TrustDirection == TrustDirection.Bidirectional) || (domainTrust.TrustDirection == TrustDirection.Inbound)))
                                {
                                    MessageBox.Show(domainTrust.TargetName);
                                    TestDomain(domainTrust.TargetName);
                                }
                            }
    
                        }
                    }
    
                }
    
    
    
                forest.Dispose();
            }
    
            static void TestDomain(string domainName)
            {
                Domain domain;
                DirectoryContext domainContext;
                Socket socket;
                bool dcOK;
    
                domainContext = new DirectoryContext(DirectoryContextType.Domain, domainName);
    
                try
                {
                    domain = Domain.GetDomain(domainContext);
                }
                catch (ActiveDirectoryObjectNotFoundException ex)
                {
                    domain = null;
                }
    
                if (domain != null)
                {
                    foreach (DomainController dc in domain.FindAllDiscoverableDomainControllers())
                    {
                        dcOK = false;
    
                        using (socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                        {
                            try
                            {
                                IAsyncResult res;
                                res = socket.BeginConnect(dc.Name, 389, null, null);
                                res.AsyncWaitHandle.WaitOne(1500, true);
    
                                if (socket.Connected)
                                {
                                    dcOK = true;
                                    socket.Close();
                                }
                            }
                            catch (SocketException ex)
                            {
                                MessageBox.Show(ex.Message);
                            }
    
                        }
                    }
    
                    domain.Dispose();
                }
                else
                {
                    MessageBox.Show("Domain is null!");
                }
    
            }

    I will verify with my IT to see what the trust relationships are, if they even come into play.  If I run the InstallShield install with involved dialogs on a machine with the computer browser service installed and running, I can see both domains.

    Any help/further pointers would be greatly appreciated.


    Thank You

    Wednesday, March 4, 2020 12:55 PM
  • Hi,

    To be honest, I haven't encountered this problem.

    I will continue to search for some information that may be useful, and if there are new discoveries, I will tell you here.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, March 5, 2020 9:58 AM