UserPrincipal.GetGroups() method throws Exception after changing DomainController - c#

We have a winforms application that gets the groups from the active directory. Now everything worked fine till we have exchanged the old domaincontroller with a new one.
Since then, our application throws an exception when the method UserPrincipal.GetGroups() is called. The Exception is thrown because it tries to connect to the old DC.
The Exception message translated:
The Server is not operational surottdc04.TOSOT.CH
Does anyone have any idea, if the old dc-information is cached somewhere or where does the application get the old information?
In the following screenshot, you can see the code-section where the Exception is thrown:
As you can see, in the watch window, there is the correct new DC surottdc06, this was propably taken from the context of the current logged user. But in the Exception, there is still the old DC surottdc04, why?
UPDATE
So far we have found out that when we pass the context as paramter to the method, then it works but without the context, the method tries to connect to the old DC.
This is one possible solution, but the question is still, where does the method get the old DC information and tries to connect there, when the method is called parameterless?
public void GetGroups()
{
var sid = WindowsIdentity.GetCurrent().User.Value;
using (var context = new PrincipalContext(ContextType.Domain, "tosot.ch"))
{
using (var userPrinciple = UserPrincipal.FindByIdentity(context, sid))
{
/*
* this works, we just pass the context which we've used to
* create the UserPrincipal instance again to fetch the groups
*/
var ret = userPrinciple.GetGroups(context);
/*
* this works NOT: when calling without context argument,
* it seems, the context used is not the same
* as the userPrinciple instance is linked to.
* Instead it uses a selfmade context with an yet exsting,
* but currently not online domain controller - why that??
* (this 'old' domain controller is currently not running,
* but it's yet not removed from the domain ...)
*/
ret = userPrinciple.GetGroups();
}
}
}

My guess is that DNS is still returning the IP of the old DC.
From the command line, run:
nslookup tosot.ch
Do you see the IP for surottdc04? If so, that's your problem.
I have experienced this problem, although I have never been in a position to fix it. These instructions might help, but it looks like an old article so it may not be done the same way anymore: https://support.microsoft.com/en-us/help/555846
Update: Or you can use C# to see what DCs it sees for the current domain. See if the old one still shows up:
foreach (DomainController dc in Domain.GetCurrentDomain().DomainControllers) {
Console.WriteLine(dc.Name);
}

Related

How To DEALLOCATE PREPARE Statement In C# Using Mysql.Data Client?

hope you guys are fine?
OK.. i am using MySQL.Data client/library to access and use MySQL database. I was using happily it for sometimes on quite a few project. But suddenly facing a new issue that causing me hold on my current project. :(
Because current project makes some (looks like it's a lot) db queries. and i am facing following exception :
Can't create more than max_prepared_stmt_count statements (current value: 16382)
i am closing and disposing the db engine/connection every time i am done with it. But getting damn confused why i am still getting this error.
​here is the sample code just to give you idea.. (trimmed out unnecessary parts)
//this loop call an API with pagination and get API response
while(ContinueSalesOrderPage(apiClient, ref pageNum, days, out string response, window) == true)
{
//this handle the API date for the current page, it's normally 500 entry per page, and it throws the error on 4th page
KeyValueTag error = HandleSalesOrderPageData(response, pageNum, out int numOrders, window);
}
private KeyValueTag HandleSalesOrderPageData(string response, int pageNum, out int numOrders, WaitWindow window)
{
numOrders = json.ArrayOf("List").Size;
//init db
DatabaseWriter dbEngine = new DatabaseWriter()
{
Host = dbHost,
Name = dbName,
User = dbUser,
Password = dbPass,
};
//connecting to database
bool pass = dbEngine.Connect();
//loop through all the entry for the page, generally it's 500 entries
for(int orderLoop = 0; orderLoop < numOrders; orderLoop++)
{
//this actually handle the queries, and per loop there could be 3 to 10+ insert/update query using prepared statements
KeyValueTag error = InsertOrUpdateSalesOrder(dbEngine, item, config, pageNum, orderLoop, numOrders, window);
}
//here as you can see, i disconnect from db engine, and following method also close the db connection before hand
dbEngine.Disconnect();
}
//code from DatabaseWriter class, as you see this method close and dispose the database properly
public void Disconnect()
{
_CMD.Dispose();
_engine.Close();
_engine.Dispose();
}
so, as you can see i close/dispose the database connection on each page processing, but still it shows me that error on 4th page. FYI, 4th page data is not the matter i checked that. If i skip the page and only process the 4th page, it process successfully.
and after some digging more in google, i found prepare statement is saved in database server and that needs to be close/deallocate. But i can't find any way to do that using MySQL.Data Client :(
following page says:
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
A prepared statement is specific to the session in which it was created. If you terminate a session without deallocating a previously prepared statement, the server deallocates it automatically. 
but that seems incorrect, as i facing the error even after closing connection on each loop
so, i am at dead end and looking for some help here? 
thanks in advance
best regards
From the official docs, the role of max_prepared_stmt_count is
This variable limits the total number of prepared statements in the server.
Therefore, you need to increase the value of the above variable, so as to increase the maximum number of allowed prepared statements in your MySQL server's configuration
Open the my.cnf file
Under the mysqld section, there is a variable max_prepared_stmt_count. Edit the value accordingly(remember the upper end of this value is 1048576)
Save and close the file. Restart MySQL service for changes to take place.
You're probably running into bug 77421 in MySql.Data: by default, it doesn't reset connections.
This means that temporary tables, user-declared variables, and prepared statements are never cleared on the server.
You can fix this by adding Connection Reset = True; to your connection string.
Another fix would be to switch to MySqlConnector, an alternative ADO.NET provider for MySQL that fixes this and other bugs. (Disclaimer: I'm the lead author.)

Renaming an existing entry in the directory gives an error saying "Naming Violation"

I'm using Novell in asp.net core 2.2 application to interact with AD. Following functions are working as expected.
Getting all users, Getting users from specific OU
Create an User
Update an User
Reset password and etc
But when i try to move the entry to new container it gives following exception
Naming Violation
((Novell.Directory.Ldap.LdapException)e).LdapErrorMessage : "00000057: LdapErr: DSID-0C090E72, comment: Error in attribute conversion operation, data 0, v4563"
Here is the code block i'm using.
var dn = $"CN={user.FirstName} {user.LastName},{this._ldapSettings.ContainerName}";
//dn => CN=arshath shameer,CN=Users,DC=wxyzdev,DC=xyzdev,DC=ca
var newRDn = $"CN={user.FirstName} {user.LastName},OU=DeletedUsers,DC=wxyzdev,DC=xyzdev,DC=ca";
// newRDn => CN=arshath shameer,OU=DeletedUsers,DC=wxyzdev,DC=xyzdev,DC=ca
using (var ldapConnection = this.GetConnection())
{
//ldapConnection.Delete(dn);
ldapConnection.Rename(dn, newRDn, dn, true);
}
I'm following this link.
There are 2 issues to fix :
RDN means relative DN : the part in the DN that actually makes an
entry distinguishable from others in the same container, for example :
CN=arshath shameer in CN=arshath
shameer,CN=Users,DC=wxyzdev,DC=xyzdev,DC=ca. In your case, since you don't want to rename but to move an entry, it doesn't change :
var newRDn = $"CN={user.FirstName} {user.LastName}";
When moving an entry - contrary to renaming - the RDN stays the same,
but the parentDN changes :
var parentDN = "OU=DeletedUsers,DC=wxyzdev,DC=xyzdev,DC=ca";
Now let's move the entry :
ldapConnection.Rename(dn, newRDN, parentDN, true);
You may also need to check whether {this._ldapSettings.ContainerName} is replaced with CN=Users,DC=wxyzdev,DC=xyzdev,DC=ca to ensure dn variable is correctly set.
I had encountered this issue. Having come across this thread from google, it was not clear to use "CN=arshath shameer".
Please use "CN=arshath shameer" instead of "CN=arshath
shameer,CN=Users,DC=wxyzdev,DC=xyzdev,DC=ca" in the newRDN parameter.
Thanx.
FRS.

How to get ExpandEnvironmentVariables to return custom variables?

I have added a custom environment variable and I'm unable to get it to return in the ExpandEnvironmentVariables.
These 2 calls work fine:
string s = Environment.GetEnvironmentVariable("TEST", EnvironmentVariableTarget.Machine);
// s = "D:\Temp2"
string path = Environment.ExpandEnvironmentVariables(#"%windir%\Temp1");
// path = "C:\Windows\Temp1"
However, this call returns the same input string:
var path = Environment.ExpandEnvironmentVariables(#"%TEST%\Temp1");
// path = "%TEST%\\Temp1"
I expect to get D:\Temp2\Temp1
What am I missing to correctly get the custom EnvironmentVariable in this last call?
Hans and Evk were correct in their comments. Since no one wanted to add an answer I'll close this question out.
For whatever reason ExpandEnvironmentVariables will not get any keys which were added after an application started. I also tested this with a running Windows Service. It was only after I restarted the service that new keys were found and populated.
This behavior is not documented in the Microsoft Documentation.

'Access Denied' when attempting DirSync with S.DS

I am trying to set up a DirSync control. Previously I have [successfully] used the methods found in the System.DirectoryServices.Protocols, but I found that the results it returned were only partial objects - I wasn't able to have it return the homeDrive attribute from a user even if I defined it in the SearchRequest's Attributes property.
Thus, I'm attempting to set up DirSync following some of the documentation and examples using System.DirectoryServices instead. I was successful in connecting to my test server (only accessible by IP), and I was successful in targeting just one OU and searching for a user, as such:
byte[] cookie = null;
root = new DirectoryEntry(
"LDAP://[MyIPHere]/OU=test ou,DC=company,DC=com", "username", "password");
//Section A - Use this section for a regular search
DirectorySearcher src = new DirectorySearcher(root);
src.SearchScope = SearchScope.Subtree;
src.Filter = "(&(objectClass=user)(sAMAccountName=myuserhere)";
//Section B - Use this section for a DirSync
//src.DirectorySynchronization = new DirectorySynchronization(
DirectorySynchronizationOptions.IncrementalValues, cookie);
//src.Filter = "(&(objectCategory=person)(objectClass=user))";
//Execute the code whichever section is used
SearchResultCollection result = src.FindAll();
int count = result.Count;
Console.WriteLine(count.ToString());
foreach (SearchResult res in result)
{
//do things
}
However, when I try to use section B instead of section A, I get an error on the line where I'm setting the int count. (I have tried passing no parameters to the constructor of src.DirectorySynchronization as in the example, same result):
COMException was unhandled
Access is denied.
I only get the error when I try to access the properties of the result object, or try to iterate. If I set a breakpoint on the int count line and look at the result object, I see the following in the value column of the result's Count:
'result.Count' threw an exception of type
'System.Runtime.InteropServices.COMException'
I have ensured that my account has the Replicating Directory Changes security access both for the specified OU and the test domain at large (and all other security access possible). I have also tried using a separate domain admin account.
I have the same issue if I try running this on our production domain, passing no credentials when constructing the DirectoryEntry object.
Considering that I can successfully retrieve other search results, what is it about this DirectorySynchronization that is causing the access issues, and why isn't it happening when I call src.FindAll()?
(I'm open to other options, but I'd like to avoid the USNChanged tracking method for now due to it returning the full objects back, and requiring additional coding on my end.)
The base of a DirSync search must be the root of a directory partition, i.e "DC=company,DC=com" in your case.
See http://msdn.microsoft.com/en-us/library/ms677626(v=vs.85).aspx
"Base of the search" in the table.
Some more good C# example for DirSync:
http://msdn.microsoft.com/en-us/magazine/cc188700.aspx#S1
See section "Finding Your Way with DirectorySearcher".
If you want to track changes only on a OU/container, yes, you will have to use USNChange.

Attempted to read or write protected memory in a Windows Forms app

As a preface, I've looked at every StackOverflow question matched by searching for this error (25 of them or so), and none of them seemed to address the problem I'm having.
I'm building up a PermissionsDialog that inherits from System.Windows.Form. Within the method that calls dialogPermissions.ShowDialog() I am retrieving some Role objects from the database and loading them into a couple of ListBoxes. That was working just fine, but now I need to override one of the properties of the Role objects I'm adding to the listboxes using this pseudocode process:
iterate over the List of Roles
look up a matching item out of a List of Profiles using List<T>.Find()
look up a property on the Profile
build up a new Role and set the Name property as needed
add the Role to a list of Roles for the PermissionsDialog
All of that goes smoothly, but when I call dialogPermissions.ShowDialog() the underlying framework code throws an AccessViolationException.
Here is what I believe to be the relevant code:
List<UserProfile> userProfiles = new List<UserProfile>();
List<Role> allRoles = new List<Role>();
dialogData.AllRoles = new List<Role>();
using (var objectContext = this.SiteContext.CreateObjectContext())
{
userProfiles = rs.UserProfiles.FindAll().ToList();
allRoles = rs.Roles.FindAll();
}
foreach (Role role in allRoles.Where(role => role.BuiltInId == (int)BuiltInRoleId.UserProfileRole)) {
var userProfile = userProfiles.Find(up => role.Id == up.Id);
var roleToAdd = new Role {
BuiltInId = role.BuiltInId,
Description = role.Description,
DirectoryEntry = role.DirectoryEntry,
Id = role.Id,
IsBuiltInRole = role.IsBuiltInRole,
Name = null != profile ? profile.DisplayName:role.Name
};
dialogData.AllRoles.Add(roleToAdd);
}
My suspicion is that this is somehow a deferred execution issue, but triggering execution by calling ToList() on dialogData.AllRoles before calling ShowDialog() doesn't resolve the issue. When I replace profile.DisplayName with a constant string I do not get the error.
Any clues what's going on under the covers here, or how to find out what's going on, or how to approach the problem differently so I can avoid it? All suggestions welcome ;-)
CONCLUSION
So here's the actual issue, I think:
Setting the Name property of the Role to null is just fine, but when the dialog tries to create a ListBoxItem out of the Role and uses the Role.Name property for the ListBoxItem's Content property (which is an Object), that can't be set as null and throws down in the framework code that's building up the dialog. Checking to make sure I had a value in there fixes the issue.
Seems like s strange exception to throw, but there you have it....
You test for profile != null, but don't test for profile.DisplayName != null so that's the first thing that comes to mind from just looking at your sample.
Standard exception finder is to go to Debug\Exceptions and check the box for break on thrown so you can see all the state when the exception is thrown.
You can stare at this code for a week and never find the reason for the AccessViolationException. Managed code does not die from processor faults like this one.
You'll need to dig out as much info you can get from the actual exception. That requires first of all that you enable unmanaged code debugging so that you can see the stack frames in the native code. Project + Properties, Debug tab, tick the "Enabled unmanaged code debugging" option.
Next, you want to make sure that you have .pdb file for any of the native Windows DLLs. Including the ones for Active Directory, somewhat suspect in this case. Tools + Options, Debugging, Symbols and enable the Microsoft Symbol Server. Press F1 if you have an older version of Visual Studio that doesn't make it a simple checkbox click.
Reproduce the crash, the call stack should give you a good hint what native code is suspect. Post it in your question if you can't make hay of it.

Categories

Resources