DirectoryEntry to change password: Different behavior between Vista/Server2008 - c#

On a Vista dev machine I used this code successfully to change user "Administrator" password:
directoryEntry.Invoke("SetPassword", "new");
When I moved it over to my Server 2008 dev machine that code did not work, and I was forced to use the following code:
directoryEntry.Invoke("ChangePassword", new object[] { "old", "new" });
My question is, why?
For both cases, I created my DirectoryEntry object as such:
DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("WinNT://{0}/{1}", computerName, username));
Thanks! 8)
In case you guys find it helpful, heres the actual code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.DirectoryServices;
using System.Security.Principal;
namespace AccountMod
{
class Program
{
static void Main()
{
Console.WriteLine("Attempting reset...\n");
try
{
String machineNameAndUser = WindowsIdentity.GetCurrent().Name.ToString();
String machineName = WindowsIdentity.GetCurrent().Name.ToString().Substring(0, machineNameAndUser.IndexOf('\\'));
Console.WriteLine("Computer's name: " + machineName);
ResetPassword(machineName, "Administrator", "new");
//ChangePassword("Administrator", "current", "new"); Console.WriteLine("Finished...");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
Console.WriteLine(e.InnerException);
}
Console.ReadKey();
}
public static void ResetPassword(string computerName, string username, string newPassword)
{
DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("WinNT://{0}/{1}", computerName, username));
directoryEntry.Invoke("SetPassword", newPassword);
//directoryEntry.Invoke("ChangePassword", new object[] { "current", "new" });
}
}
}

Are you (or could you upgrade to) .NET 3.5? The AD integration for users, groups, computers has been massively improved in .NET 3.5 - check out the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 for details.
In your case, you could do something like:
// establish context for local machine
PrincipalContext ctx = new PrincipalContext(ContextType.Machine);
// find the "Administrator" account
UserPrincipal admin = UserPrincipal.FindByIdentity(ctx, "Administrator");
// set the password to a new value
admin.SetPassword("new-top-secret-password");
admin.Save();
and you're done! The WinNT: provider is very limited in what it can do and should be avoided if ever possible.

Check user properties for which you want to set password, if
user cannot change password
property is checked then u cant set password by using directoryEntry.Invoke("SetPassword", "new");Use admin credential while creating DirectoryEntry object or uncheck " user cannot change password" property

Related

Authorization problem with DirectoryEntry and ActiveDirectorySecurity

I am writing a class to set or remove access rules to protect or unprotect objects from accidental removal, using ActiveDirectorySecurity.AddAccessRule and ActiveDirectorySecurity.RemoveAccessRule.
My class works fine if I provide the username and password of an admin account to the DirectoryEntry (which I don't want to do), but if I don't provide username and password it throws an error
System.DirectoryServices.DirectoryServicesCOMException: A constraint violation occurred
My default account however can change the protect object flag using the Active Directory Users and Computers app without any problems.
Any ideas on why this could be happening?
using System;
using System.DirectoryServices;
using System.Security.AccessControl;
using System.Security.Principal;
namespace test123
{
internal class Test124
{
internal static void RemoveAccidentialProtection()
{
string dn = "CN=XXX,OU=XXX,OU=XXX,OU=XXX,OU=XXX,DC=XXX,DC=XXX";
using (DirectoryEntry ent = new DirectoryEntry("LDAP://XXX:nnn/" + dn))
{
IdentityReference everyOneAccount = new NTAccount("Everyone").Translate(typeof(SecurityIdentifier)); //S - 1 - 1 - 0
ActiveDirectoryAccessRule objAce = new ActiveDirectoryAccessRule(everyOneAccount, ActiveDirectoryRights.Delete | ActiveDirectoryRights.DeleteTree, AccessControlType.Deny);
ent.ObjectSecurity.RemoveAccessRule(objAce);
ent.CommitChanges();
}
}
}
}
I found a post that says DirectoryEntry.CommitChanges defaults to setting ownership information which isn't allowed for regular users, so you need to set DirectoryEntry to only write the ACL changes. Put the following line just before the call to CommitChanges:
ent.Options.SecurityMasks = SecurityMasks.Dacl;

How to resolve this error "ERROR_BAD_USERNAME" in WNetAddConnection2?

My problem is to copy file from one system to another system on the same network. I googled for the above problem, I started working with Mark Brackett's answer.
Now i am planning to copy the files from my system to another system, but i am getting following error codes 53, 67, 2202. I resolved the first two error codes successfully. Now i am stuck with 2202. please look into the below code.
NetworkCredential credentials = new NetworkCredential(#"\\192.168.0.110\", "krishna4");
private void btnClick_Click(object sender, EventArgs e)
{
// NetwrokConnection(string networkName, NetworkCredential credentials)
using (new NetworkConnection("\\\\10.235.115.210\\d", credentials)) ;
System.IO.File.Copy("D:\\English\\parts.oxps", #"\\192.168.0.110\test\parts.oxps", true);
}
Please help to resolve the problem. Thanks in advance.
I think your connection credentials may be wrong.it may be invalid user name.
I suggest to refer following link:
ERROR_BAD_USERNAME
WNetUseConnection2 in C#
How to finish this implementation of creating a network share using WNetAddConnection2?
ERROR_BAD_USERNAME :The specified user name is not valid.
Here is Sample Code;
using System;
using System.IO;
using System.Net;
class Program
{
static void Main(string[] args)
{
var networkPath = #"//server/share";
var credentials = new NetworkCredential("username", "password");
using (new NetworkConnection(networkPath, credentials))
{
var fileList = Directory.GetFiles(networkPath);
}
foreach (var file in fileList)
{
Console.WriteLine("{0}", Path.GetFileName(file));
}
}
}

Generate GPO Report From Untrusted Domain

I'm calling LogonUser with LOGON_TYPE_NEW_CREDENTIALS and LOGON32_PROVIDER_WINNT50 to get my thread to impersonate a user in the other domain. I'm able to connect to remote file shares and everything else just fine into the untrusted domain.
The problem I'm running into now is when I use GPMGMTLib to generate a GPO report I keep getting exception "HRESULT: 0x80072020" when it calls GenerateReport().
using GPMGMTLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace CrossDomainWork
{
class Program
{
static void Main(string[] args)
{
ImpersonationContext context = new ImpersonationContext("ourdmzdomain.com", "dmzuser", "dmzpassword");
context.Start();
GPM gpm = new GPM();
var constants = gpm.GetConstants();
var domain = gpm.GetDomain("ourdmzdomain.com", "", constants.UseAnyDC);
var gpo = domain.GetGPO("{31B2F340-016D-11D2-945F-00C04FB984F9}");
object missing = Type.Missing;
var result = gpo.GenerateReport(GPMReportType.repHTML, ref missing, out missing).Result;
context.Stop();
}
}
}
I have no experience here, so this is just a guess.
Looking at the documentation for GenerateReport, the last two parameters are pvarGPMProgress (for reporting progress), and pvarGPMCancel (some kind of cancellation token).
You are passing the same object for both. I wonder if that's what's making it choke. You can try creating a second object.
Maybe it's also possible that it doesn't like getting Type.Missing as the value. You can try just setting them to null.
Also, does the group policy have any special permissions on it?
What namespace is that ImpersonationContext in that you're using? I can't find it. We do have an untrusted domain at work that I can test with, if I can get your code to compile.
Edit:
If you have SetLastError = true in your DllImport statements, then you can use Marshal.GetLastWin32Error() to get some additional details. For example:
try {
result = gpo.GenerateReport(GPMReportType.repHTML, ref missing, out missing).Result;
} catch {
var win32 = new Win32Exception(Marshal.GetLastWin32Error());
Console.Write(win32.Message);
}
For me, it tells me
An attempt was made to reference a token that does not exist
Which doesn't solve the puzzle, but it's another piece to the puzzle.

Apps not running on different machines

I have this code:
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
namespace Nameddd
{
class Program
{
static void Main(string[] args)
{
Hosts();
Console.WriteLine("Loading..");
Console.WriteLine("Your computer is not supported");
Console.ReadKey();
}
static void Hosts()
{
{
using (StreamWriter w = File.AppendText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers/etc/hosts")))
{
w.WriteLine("SOME_IP domain.com");
}
}
This program is working for me but apparently not on every system. I used VS 2015 community on Windows 10. On another computer my friend (with windows 7) - also working.
But for someone with Windows 10 it is not working. Application is not running, "loading cursor" - that's it. If I'm trying to delete the .exe it shows a message box with text like "process already running".
Make sure you are running the code or executable as administrator.
You probably opened the file but couldn't save the changes to the file for the friend that the code failed.
from another post from here you can check it like this:
using System.Security.Principal;
public bool IsUserAdministrator()
{
bool isAdmin;
try
{
WindowsIdentity user = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(user);
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch (UnauthorizedAccessException ex)
{
isAdmin = false;
}
catch (Exception ex)
{
isAdmin = false;
}
return isAdmin;
}

Cannot authenticate against Apache DS using C# and LdapConnection?

Problem
I installed and configured a ApacheDS server running ldap. This was a huge step forward for me in teaching myself ldap. However, the following C# console code returns the following error:
System.DirectoryServices.Protocols.LdapException {"The supplied credential is invalid"}
My code is to use this sample code to authenticate a sample user.
Code
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SampleLdapAuthentication
{
class Program
{
static void Main(string[] args)
{
RunLdap run = new RunLdap("localhost", "organization", 635, "hderp", "spaceballs1234");
bool result = run.ValidateCredentials();
if(result)
{
Console.WriteLine("Authentication Succeeded");
}
else
{
Console.WriteLine("Authentication Failed");
}
}
}
}
SampleLdapAuthentication.cs
using System;
using System.Collections.Generic;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace SampleLdapAuthentication
{
public class RunLdap
{
private static string _domainController;
private static string _domain;
private static int _port;
private static string _userName;
private static string _userPassword;
//Constructor. Takes the domain controller, domain, port, username, and password and then calls Ldap Method to run authentication
public RunLdap(string domainController, string domain, int port, string userName, string userPassword)
{
_domainController = domainController;
_domain = null;
_port = port;
_userName = userName;
_userPassword = userPassword;
}
public bool ValidateCredentials()
{
LdapDirectoryIdentifier ldi = new LdapDirectoryIdentifier(_domainController, _port);
NetworkCredential networkCredential = new NetworkCredential(_userName, _userPassword, _domain);
try
{
//We use using so we dispose the object as soon as it goes out of scope
using (LdapConnection connection = new LdapConnection(ldi))
{
//connection.SessionOptions.SecureSocketLayer = true;
connection.AuthType = AuthType.Kerberos;
connection.Bind(networkCredential);
//Not sure what this is doing
}
return true;
}
catch(LdapException ldapException)
{
return false;
}
return false;
}//End of ValidateCredentials
}
}
LDAP Server Details
Notes
The following are worth noting in what I am doing:
I followed this tutorial in creating the server and DIT.
According to my understanding ApacheDS supports keberos out of the box now, so my authentication type should be fine. That is, AuthType
It fails on connection.Bind() method
I am thinking maybe there is something wrong with how I am entering in the credentials and that my C# code is fine. That is why I included the server AD information. I am new to LDAP and using it to authenticate users, so I appreciate your help.
You're not using the distinguished name of the user. When you create your NetworkCredential object, you should be using the distingushed name of the user, in this case, cn=Herp Derp,ou=users,o=organization instead of hderp. The LDAP doesn't know where to look for hderp without the o and ou values.

Categories

Resources