//Function to create domain level dirContext object
        public static DirectoryContext CreateDirectoryContext(
                                        string DomainControllerName,
                                        string rootDN,
                                        string UserName,
                                        string Password,
                                        int portNumber,
                                        bool usingSimpleBind,
                                        out string errorMessage)
        {
            int ret = -1;

            errorMessage = null;

            string sDomainControllerIP = null;
            IPHostEntry domainControllerEntry=null;

            try
            {
                if (DomainControllerName != null)
                {
                    domainControllerEntry = Dns.GetHostEntry(DomainControllerName);
                }
                else
                {
                    return null;
                }
            }
            catch(Exception ex)
            {
                errorMessage =
                    String.Format(
                    "The specified domain either does not exist or DNS could not resolve the address of the domain controller : {0}",
                    DomainControllerName);
                Logger.Log("DirectoryContext.CreateDirectoryContext():" + ex.Message);
                Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                //Logger.ShowUserError(errorMessage);
                return null;
            }

            if (domainControllerEntry != null && domainControllerEntry.AddressList.Length > 0)
            {
                sDomainControllerIP = domainControllerEntry.AddressList[0].ToString();
            }
            else
            {
                errorMessage =
                    String.Format(
                    "DirectoryContext.CreateDirectoryContext(): Could not resolve address of domain controller : {0}",
                    DomainControllerName);
                //Logger.ShowUserError("DirectoryContext.CreateDirectoryContext(): Could not resolve address of domain controller: {0}");
                Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                errorMessage = "";
                return null;
            }

            IntPtr ld = LdapAPI.ldap_open(sDomainControllerIP, portNumber);
            if (ld == IntPtr.Zero)
            {
                errorMessage =
                    "The specified domain either does not exist or could not be contacted.  " +
                    "Please contact your system administrator to verify that your domain is " +
                    "properly configured and is currently online.";
                Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                errorMessage = "";
                //Logger.ShowUserError(errorMessage);
                return null;
            }

            //LdapTimeVal timeout = new LdapTimeVal(1, 0);
            ////IntPtr ptrTimeout = IntPtr.Zero;
            ////ptrTimeout = Marshal.AllocHGlobal(Marshal.SizeOf(timeout));
            ////Marshal.WriteInt32(ptrTimeout, timeout.);
            //ret = LdapAPI.ldap_connect(ld, timeout.ConvertToUM());
            //if (BailOnLdapError("LdapAPI.ldap_connect :", ret, out errorMessage))
            //{
            //    Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
            //    errorMessage = "";
            //    return null;
            //}

            LdapHandle ldapHandle = new LdapHandle(ld);

            string distinguishedName = string.Format("cn={0},cn=Users,{1}", UserName, rootDN);
            if (!String.IsNullOrEmpty(UserName) && !UserName.Equals("administrator", StringComparison.InvariantCultureIgnoreCase))
                distinguishedName = UserName;

            int version = LDAP_VERSION3;
            IntPtr ptrVersion = IntPtr.Zero;
            ptrVersion = Marshal.AllocHGlobal(Marshal.SizeOf(version));
            Marshal.WriteInt32(ptrVersion, version);
            ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, ptrVersion);
            if(BailOnLdapError("ldap_set_option OPT_PROTOCOL_VERSION :", ret, out errorMessage))
            {
                Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                errorMessage = "";
                return null;
            }

            ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_REFERRALS, IntPtr.Zero);
            if(BailOnLdapError("ldap_set_option LDAP_OPT_REFERRALS :", ret, out errorMessage))
            {
                Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                errorMessage = "";
                return null;
            }

            if (!String.IsNullOrEmpty(Password))
            {
                usingSimpleBind = Configurations.SSOFailed = true;
            }

            if (usingSimpleBind)
            {
                if (Configurations.currentPlatform == LikewiseTargetPlatform.Windows)
                {
                    ret = LdapAPI.ldap_bind_s(ld, distinguishedName, Password, (ulong)LDAP_AUTHWindows.LDAP_AUTH_SIMPLE);
                }
                else
                {
                    ret = LdapAPI.ldap_bind_s(ld, distinguishedName, Password, (ulong)LDAP_AUTHLinux.LDAP_AUTH_SIMPLE);
                }
                if (BailOnLdapError("", ret, out errorMessage))
                {
                    Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                    return null;
                }
            }
            else  /***GSS-bind***/
            {
                if (Configurations.currentPlatform != LikewiseTargetPlatform.Windows)
                {
                    //set GSS-Remote Principal Name

                    //char ber_pvt_opt_on;    /* used to get a non-NULL address for *_OPT_ON */
                    ///* option on/off values */
                    //#define LDAP_OPT_ON           ((void *) &ber_pvt_opt_on)
                    //#define LDAP_OPT_OFF    ((void *) 0)
                    //status = ldap_set_option(ld, LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL, LDAP_OPT_ON);

                    char ber_pvt_opt_on = '1';
                    IntPtr ptrRemotePrincipalflags = IntPtr.Zero;
                    ptrRemotePrincipalflags = Marshal.AllocHGlobal(Marshal.SizeOf(ber_pvt_opt_on));
                    Marshal.WriteInt32(ptrRemotePrincipalflags, ber_pvt_opt_on);
                    ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL, ptrRemotePrincipalflags);
                    if (BailOnLdapError("DirectoryContext GSS-Bind: ldap_set_option LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL, ptrRemotePrincipalflags=" + ptrRemotePrincipalflags,
                    ret, out errorMessage))
                    {
                        Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                        errorMessage = "";
                        return null;
                    }
                }

                //set GSS-SPNEGO options
                int secflags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT;

                IntPtr ptrSecflags = IntPtr.Zero;
                ptrSecflags = Marshal.AllocHGlobal(Marshal.SizeOf(secflags));
                Marshal.WriteInt32(ptrSecflags, secflags);
                ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_SSPI_FLAGS, ptrSecflags);
                if (BailOnLdapError("DirectoryContext GSS-Bind: ldap_set_option LDAP_OPT_SSPI_FLAGS, secflags=" + secflags,
                    ret, out errorMessage))
                {
                    Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                    errorMessage = "";
                    return null;
                }

                if (Configurations.currentPlatform != LikewiseTargetPlatform.Windows)
                {
                    secflags |= ISC_REQ_INTEGRITY;

                    ptrSecflags = IntPtr.Zero;
                    ptrSecflags = Marshal.AllocHGlobal(Marshal.SizeOf(secflags));
                    Marshal.WriteInt32(ptrSecflags, secflags);
                    ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_SSPI_FLAGS, ptrSecflags);
                    if (BailOnLdapError("DirectoryContext GSS-Bind: ldap_set_option LDAP_OPT_SSPI_FLAGS, secflags=" + secflags,
                        ret, out errorMessage))
                    {
                        Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                        errorMessage = "";
                        return null;
                    }

                    secflags |= ISC_REQ_CONFIDENTIALITY;

                    ptrSecflags = IntPtr.Zero;
                    ptrSecflags = Marshal.AllocHGlobal(Marshal.SizeOf(secflags));
                    Marshal.WriteInt32(ptrSecflags, secflags);
                    ret = LdapAPI.ldap_set_option(ld, LDAP_OPT_SSPI_FLAGS, ptrSecflags);
                    if (BailOnLdapError("DirectoryContext GSS-Bind: ldap_set_option LDAP_OPT_SSPI_FLAGS, secflags=" + secflags,
                        ret, out errorMessage))
                    {
                        Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                        errorMessage = "";
                        return null;
                    }
                }
                if (Configurations.currentPlatform == LikewiseTargetPlatform.Windows)
                {
                    ret = LdapAPI.ldap_bind_s(ld, null, null, (ulong)LDAP_AUTHWindows.LDAP_AUTH_NEGOTIATE);
                }
                else
                {
                    ret = LdapAPI.ldap_bind_s(ld, null, null, (ulong)LDAP_AUTHLinux.LDAP_AUTH_NEGOTIATE);
                }
                if (BailOnLdapError("DirectoryContext GSS-Bind:ldap_bind_s :", ret, out errorMessage))
                {
                    Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                    errorMessage = "";
                    return null;
                }
            }

            //try to figure out the DC that serves as GC
            string configurationName = null;
            //searching with baseDn="" allows ldap to access the domain “RootDSE”.
            //Without passing that, it cannot access the configurationNamingContext
            DirectoryContext dirContext = new DirectoryContext(
                                DomainControllerName,
                                rootDN,
                                distinguishedName,
                                UserName,
                                Password,
                                ldapHandle,
                                portNumber);

            dirContext._domainControllerIP = sDomainControllerIP;
            LdapMessage ldapMessage;
            string gcServer = DomainControllerName;

            Logger.Log("root query is started querying ", Logger.ldapLogLevel);
            IntPtr MessagePtr;
            ret = LdapAPI.ldap_search_s(ld,
                                        "",
                                        (int)LdapAPI.LDAPSCOPE.BASE,
                                        "(objectClass=*)",
                                        null,
                                        0,
                                        out MessagePtr);

            ldapMessage = new LdapMessage(ldapHandle, MessagePtr);
            Logger.Log("root query is finished querying " + ret, Logger.ldapLogLevel);

            List<LdapEntry> ldapEntries = (ldapMessage != null ? ldapMessage.Ldap_Get_Entries() : null);
            Logger.Log("root query is finished querying with ldapEntries count : " + ldapEntries, Logger.ldapLogLevel);

            #region //Obtaining RootDSE attributes
            if (ldapEntries != null && ldapEntries.Count > 0)
            {
                LdapEntry rootDseEntry = ldapEntries[0];

                LdapValue[] values = rootDseEntry.GetAttributeValues("defaultNamingContext", dirContext);

                if (values != null && values.Length > 0)
                {
                    dirContext.DefaultNamingContext = values[0].stringData;
                }
                Logger.Log("defaultNamingContext is " + dirContext.DefaultNamingContext, Logger.ldapLogLevel);

                values = rootDseEntry.GetAttributeValues("schemaNamingContext", dirContext);

                if (values != null && values.Length > 0)
                {
                    dirContext.SchemaNamingContext = values[0].stringData;
                }
                Logger.Log("schemaNamingContext is " + dirContext.SchemaNamingContext, Logger.ldapLogLevel);

                values = rootDseEntry.GetAttributeValues("dnsHostName", dirContext);

                if (values != null && values.Length > 0)
                {
                    dirContext.DnsHostName = values[0].stringData;
                }
                Logger.Log("dnsHostName is " + dirContext.DnsHostName, Logger.ldapLogLevel);

                values = rootDseEntry.GetAttributeValues("rootDomainNamingContext", dirContext);

                if (values != null && values.Length > 0)
                {
                    dirContext.RootDomainNamingContext = values[0].stringData;
                }
                Logger.Log("dnsHostName is " + dirContext.RootDomainNamingContext, Logger.ldapLogLevel);

                values = rootDseEntry.GetAttributeValues("configurationNamingContext", dirContext);

                if (values != null && values.Length > 0)
                {
                    configurationName = values[0].stringData;
                }
                Logger.Log(
                    "configurationNamingContext is " + configurationName,
                    Logger.ldapLogLevel);

                values = rootDseEntry.GetAttributeValues("SupportedSASLMechanisms", dirContext);

                if (values != null && values.Length > 0)
                {
                    _supportedSASLMechanisms = new string[values.Length];
                    int index = 0;

                    foreach (LdapValue value in values)
                    {
                        _supportedSASLMechanisms[index] = value.stringData;

                        Logger.Log(
                                    "SupportedSASLMechanisms is " + value.stringData,
                                    Logger.ldapLogLevel);
                        index++;
                    }
                }

                dirContext.ConfigurationNamingContext = configurationName;

            #endregion

                ret = LdapAPI.ldap_search_s(ld,
                                        configurationName,
                                        (int)LdapAPI.LDAPSCOPE.BASE,
                                        "(&(objectcategory=ntdsdsa)(options=1))",
                                        new string[] { "distinguishedName", null },
                                        0,
                                        out MessagePtr);

                ldapMessage = new LdapMessage(ldapHandle, MessagePtr);

                if(BailOnLdapError("ldap_search_s :", ret, out errorMessage))
                {
                    Logger.Log("DirectoryContext.CreateDirectoryContext(): " + errorMessage);
                    errorMessage = "";
                    return null;
                }

                ldapEntries = (ldapMessage != null ? ldapMessage.Ldap_Get_Entries() : null);

                if (ldapEntries != null && ldapEntries.Count > 0)
                {
                    //we only check the first one, then we quit finding others (when we do optimization, this algorithm shall be a lot more complicated
                    LdapEntry ldapNextEntry = ldapEntries[0];

                    values = ldapNextEntry.GetAttributeValues("distinguishedName", dirContext);

                    if (values != null && values.Length > 0)
                    {
                        string dn = values[0].stringData;
                        string[] splits1 = dn.Split(',');
                        string[] splits2 = rootDN.Split(',');

                        gcServer = splits1[1].Substring(3).ToLower();
                        foreach (string str in splits2)
                            gcServer = string.Concat(gcServer, ".", str.Substring(3).ToLower());

                        Logger.Log(
                            "global catelog server is " + gcServer,
                            Logger.ldapLogLevel);
                    }
                }
            }

            dirContext.GCServername = gcServer;
            dirContext.BindMethod = usingSimpleBind;

            ldapHandle.DirectoryContext = dirContext;

            return dirContext;
        }
        protected DirectoryContext(
                    string ServerName,
                    string rootDN,
                    string DistinguishedName,
                    string UserName,
                    string Password,
                    LdapHandle ldapHandle,
                    int portNumber)
        {
            _rootDN = rootDN;

            string[] domainDNcom = _rootDN.Split(',');

            string domainName = "";
            foreach (string str in domainDNcom)
            {
                string temp = string.Concat(str.Substring(3), ".");
                domainName = string.Concat(domainName, temp);
            }

            domainName = domainName.Substring(0, domainName.Length - 1);

            _domainName = domainName;

            _domainControllerName = ServerName;
            _distinguishedName = DistinguishedName;
            _userName = UserName;
            _password = Password;
            _ldapHandle = new LdapHandle(ldapHandle.Handle, this);
            _portNumber = portNumber;
        }
        public DirectoryContext(DirectoryContext dirContext)
        {

            _rootDN = dirContext.RootDN;

            string[] domainDNcom = _rootDN.Split(',');

            string domainName = "";
            foreach (string str in domainDNcom)
            {
                string temp = string.Concat(str.Substring(3), ".");
                domainName = string.Concat(domainName, temp);
            }

            domainName = domainName.Substring(0, domainName.Length - 1);

            _domainName = domainName;

            _domainControllerName = dirContext.DomainControllerName;
            _distinguishedName = dirContext.DistinguishedName;
            _userName = dirContext.UserName;
            _password = dirContext.Password;
            _ldapHandle = new LdapHandle(dirContext.LdapHandle.Handle, this);
            _portNumber = dirContext.PortNumber;
        }
        public LdapMessage(LdapHandle ldapHandle, IntPtr ldapMessage)
		{
			_ldapHandle = ldapHandle;
			_ldapMessage = ldapMessage;
		    _dircontext = null;
        }