In C# I would like test the availability of a network path, what authentication needed. I am using the following function:
private bool TestDrive(string path,string userName,string domain, string password)
{
if (userName == "")
return true;
//else authentication needed
try
{
using (new CImpersonator(userName, domain, password))
{
using (FileStream fs = File.Create(path+"\\1.txt"))
{ }
File.Delete(path + "\\1.txt");
}
return true;
}
catch (Exception ex)
{
return false;
}
}
public CImpersonator(
string userName,
string domainName,
string password,
bool checkUserName = true)
{
//Check if user exists
if (checkUserName && !CCheckUsername.UserExists(userName))
return;
this.ImpersonateValidUser(userName, domainName, password);
}
private void ImpersonateValidUser(
string userName,
string domain,
string password)
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, (int)System.Management.ImpersonationLevel.Impersonate, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
_impersonationContext = tempWindowsIdentity.Impersonate();
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = (IntPtr)System.Diagnostics.Process.GetCurrentProcess().Id;
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ALL_ACCESS, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, SE_SYSTEMTIME_NAME, ref tp.Luid);
retVal = AdjustTokenPrivileges(token, false, ref tp, Marshal.SizeOf(typeof(TokPriv1Luid)), IntPtr.Zero, IntPtr.Zero);
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
The problem is that when I use this for test a network path in an another domain, then the TestDrive function returns false. Of course the domain, username and password are good, the user rights are good.
It is strange that the function works good, when I test it in the same domain.
Thank you for all ideas!
I would first try the following:
Folder.Exists(String Path);
This will however only work on a Path where you have read access, so if the network path isn't mapped with the credentials this method will return false, but you can use the above method and if it returns false, map the network path (this question answersthe how-to on that) with those different credentials
and then perform the:
Folder.Exists(String Path);
once more. Afterwards you can disconnect the network drive again.
Related
I need to check if service "Advice" has its status running on said server. I made a method that does just that:
public static bool CheckServicesFromServer(string pServicos)
{
ServiceController service = new ServiceController();
List<string> Servicos = pServicos.Split(',').Select(p => p.Trim()).ToList();
if (Config.BaseLogin == BasesSistema.QualityLogin)
service.MachineName = "quality";
if (Config.BaseLogin == BasesSistema.TS02Login)
service.MachineName = "ts02";
if (Config.BaseLogin == BasesSistema.TS03Login)
service.MachineName = "ts03";
if (Config.BaseLogin == BasesSistema.LocalHost)
service.MachineName = Environment.MachineName;
try
{
foreach (var item in Servicos)
{
service.ServiceName = item;
if ((service.Status.Equals(ServiceControllerStatus.Stopped)) || (service.Status.Equals(ServiceControllerStatus.StopPending)))
{
File.AppendAllText(StatusLog.StatusLocation, "O servico " + service.ServiceName + " está parado. a Regra não será gerada.");
throw new Exception();
}
if (service.Status.Equals(ServiceControllerStatus.Running))
{
File.AppendAllText(StatusLog.StatusLocation, "O serviço " + service.ServiceName + "está rodando perfeitamente.");
}
}
}
catch (Exception e)
{
Log.WriteErrorLog(e.Message);
throw new Exception(e.Message);
}
return true;
}
The thing is, when I run the test, it says "Access Denied", and throws an exception. When I add my user (The user from the computer which is running the application) as an Adm at the server, it runs fine.
Is there a way to authenticate my computer so it can have permission to access the server and check its service status?
Thanks to Krik, I found the solution. It's as simple as addind this class:
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Security.Permissions;
public class ImpersonateUser
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
String lpszUsername,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
private static IntPtr tokenHandle = new IntPtr(0);
private static WindowsImpersonationContext impersonatedUser;
// If you incorporate this code into a DLL, be sure to demand that it
// runs with FullTrust.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Impersonate(string domainName, string userName, string password)
{
//try
{
// Use the unmanaged LogonUser function to get the user token for
// the specified user, domain, and password.
const int LOGON32_PROVIDER_DEFAULT = 0;
// Passing this parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
tokenHandle = IntPtr.Zero;
// ---- Step - 1
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(
userName,
domainName,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref tokenHandle); // tokenHandle - new security token
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
// ---- Step - 2
WindowsIdentity newId = new WindowsIdentity(tokenHandle);
// ---- Step - 3
{
impersonatedUser = newId.Impersonate();
}
}
}
// Stops impersonation
public void Undo()
{
impersonatedUser.Undo();
// Free the tokens.
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
}
internal void Impersonate()
{
throw new NotImplementedException();
}
}
And I Just had to call it like this:
public static bool CheckServicesFromServer(string pServicos)
{
ImpersonateUser Iu = new ImpersonateUser();
ServiceController service = new ServiceController();
List<string> Servicos = pServicos.Split(',').Select(p => p.Trim()).ToList();
if (Config.BaseLogin == BasesSistema.QualityLogin)
service.MachineName = "quality";
if (Config.BaseLogin == BasesSistema.TS02Login)
service.MachineName = "ts02";
if (Config.BaseLogin == BasesSistema.TS03Login)
service.MachineName = "ts03";
if (Config.BaseLogin == BasesSistema.LocalHost)
service.MachineName = Environment.MachineName;
Iu.Impersonate(Config.Dominio, Config.LoginMaster, Config.SenhaMaster);
try
{
foreach (var item in Servicos)
{
service.ServiceName = item;
if ((service.Status.Equals(ServiceControllerStatus.Stopped)) || (service.Status.Equals(ServiceControllerStatus.StopPending)))
{
Flag = true;
File.AppendAllText(StatusLog.StatusLocation, "O servico " + service.ServiceName + " está parado. a Regra não será gerada. <br />");
throw new Exception();
}
if (service.Status.Equals(ServiceControllerStatus.Running))
{
File.AppendAllText(StatusLog.StatusLocation, "O serviço " + service.ServiceName + " está rodando perfeitamente. <br />");
}
}
Iu.Undo();
}
catch
{
Iu.Undo();
Log.WriteErrorLog("Não é possível abrir o Gerenciador de Controle de Serviços no Computador '" + service.MachineName + "'. <br />");
return false;
}
return true;
}
My Config Class holds the information of the Domain, User and PassWord, and it worked perfectly.
I am writing an installer that installs SQL, beforehand a user is prompted to enter the SA username/password which will be created for them. When SQL installs it verifies this password against the Active Directory policy and will fail if it doesnt match.
What I want to do is verify the password input by the user is valid before proceeding to install SQL.
How can I validate a password is correct against Active Directory rules?
Note I do not have a login to verify as per this answer, but simply a password to verify.
I am currently trying this, but writing "password" which I know is not allowed doesnt throw an exception
try
{
System.DirectoryServices.DirectoryEntry localMachine = new System.DirectoryServices.DirectoryEntry("WinNT://" + Environment.MachineName);
ListPasswordPolicyInfo(Environment.MachineName);
System.DirectoryServices.DirectoryEntry newUser = localMachine.Children.Add("localuser", "user");
newUser.Invoke("SetPassword", new object[] { "3l!teP#$$w0RDz" });
newUser.Invoke("SetPassword", new object[] { "password" });
//newUser.CommitChanges();
//Console.WriteLine(newUser.Guid.ToString());
localMachine.Close();
newUser.Close();
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
After a lot of pain I have found the C# solution to this using NetValidatePasswordPolicy. Use the supporting structs off of PInvoke and the following code
public static NET_API_STATUS ValidatePassword(string password)
{
var outputArgs = new NET_VALIDATE_OUTPUT_ARG();
var inputArgs = new NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG();
IntPtr inputPointer = IntPtr.Zero;
IntPtr outputPointer = IntPtr.Zero;
try
{
inputArgs.PasswordMatched = true;
inputArgs.ClearPassword = Marshal.StringToBSTR(password);
// If using a secure string
////inputArgs.ClearPassword = Marshal.SecureStringToBSTR(secureStringPassword);
inputPointer = Marshal.AllocHGlobal(Marshal.SizeOf(inputArgs));
Marshal.StructureToPtr(inputArgs, inputPointer, false);
NET_API_STATUS status = NetValidatePasswordPolicy(System.Environment.MachineName, IntPtr.Zero, NET_VALIDATE_PASSWORD_TYPE.NetValidatePasswordChange, inputPointer, ref outputPointer);
if (status == NET_API_STATUS.NERR_Success)
{
outputArgs = (NET_VALIDATE_OUTPUT_ARG)Marshal.PtrToStructure(outputPointer, typeof(NET_VALIDATE_OUTPUT_ARG));
if (outputArgs.ValidationStatus == NET_API_STATUS.NERR_Success)
{
// Ok
}
return outputArgs.ValidationStatus;
}
else
{
return status;
}
}
finally
{
if (outputPointer != IntPtr.Zero)
{
NetValidatePasswordPolicyFree(ref outputPointer);
}
if (inputArgs.ClearPassword != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(inputArgs.ClearPassword);
}
if (inputPointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(inputPointer);
}
}
}
try{
var userName = "bob";
using (var pc = new PrincipalContext(ContextType.Domain)
{
var user = UserPrincipal.FindByIdentity(pc, userName);
user.ChangePassword(oldpassword, newpassword); //Checks password policy
//or
user.SetPassword(newpassword); //Not positive checks password policy but I believe it 2.
}
}
catch(PasswordException ex)
{
//do something with ex
}
Structure of directory is like,
ou=system,ou=valeteck,cn=mayank
I have to check that the password entered by user is correct and match with user's password i.e of mayank.
But system and cn='mayank' have different passwords. If I create directory entry object with password of cn I didn't get authenticate with ldap but if I use system directory and its password I get authenticate but then how to check user's password.
There is even a more simple method provided to you by the Windows API using advapi32.dll .
Example:
[DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LogOnUser(string lpszUserName, string lpszDomain, string lpszPassword,
int dwLogOnType, int dwLogOnProvider, ref IntPtr phToken);
this method returns simply true or false if the user is indeed in the domain and has entered its Password correctly.
Then you just make your own sign in method checking authentication against advapi32.dll .
public ActionResult SignIn(SignInModel model)
{
string domainName = CheckSignIn.GetDomainName(model.User.UserName);
string userName = CheckSignIn.GetUserName(model.User.UserName);
IntPtr token = IntPtr.Zero;
bool result = CheckSignIn.LogOnUser(userName, domainName, model.User.UniqueUserCode, 2, 0, ref token);
if (result)
{
if (!string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]) && Request.QueryString["ReturnUrl"] != "/")
{
FormsAuthentication.RedirectFromLoginPage(model.User.UserName, false);
}
else
{
FormsAuthentication.SetAuthCookie(model.User.UserName, false);
return RedirectToAction("MyVoyages", "Voyage");
}
}
return SignIn(true);
}
simple, yet powerfull.
private bool LoginS(string userName, string password)
{
bool authentic = false;
try
{
DirectoryEntry entry = new DirectoryEntry(LDAP-Path, userName, password, AuthenticationTypes.Secure);
authentic = true;
Console.WriteLine("Authentication successful");
}
catch (DirectoryServicesCOMException e)
{
_logger.Error("Authentification error", e);
//User doesnt exist or input is false
}
return authentic;
}
ASP.NET: Impersonate against a domain on VMWare
This question is what I am asking, but the answer does not provide details on how the _token is derived. It seems to only use WindowsIdentity.GetCurrent().Token so there's no impersonation happening.
Can I impersonate a user on a different Active Directory domain in .NET?
This next question has conflicting answers, with the accepted one bearing a comment "I'm beginning to suspect that my problem lies elsewhere." Not helpful.
LogonUser works only for my domain
This next question seems to imply it is not possible, but it deals with 2 domains so I am not sure if it is relevant.
My real question is:
Is it possible? And if so,
How? or Where did I go wrong?
What I have tried so far is, using the code from http://msdn.microsoft.com/en-us/library/chf6fbt4%28v=VS.80%29.aspx
bool returnValue = LogonUser(user, domain, password,
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
// after this point, returnValue = false
The Win32 error is
Logon failure: unknown user name or bad password
Very few posts suggest using LOGON_TYPE_NEW_CREDENTIALS instead of LOGON_TYPE_NETWORK or LOGON_TYPE_INTERACTIVE. I had an impersonation issue with one machine connected to a domain and one not, and this fixed it.
The last code snippet in this post suggests that impersonating across a forest does work, but it doesn't specifically say anything about trust being set up. So this may be worth trying:
const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
bool returnValue = LogonUser(user, domain, password,
LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,
ref tokenHandle);
MSDN says that LOGON_TYPE_NEW_CREDENTIALS only works when using LOGON32_PROVIDER_WINNT50.
this works for me, full working example (I wish more people would do this):
//logon impersonation
using System.Runtime.InteropServices; // DllImport
using System.Security.Principal; // WindowsImpersonationContext
using System.Security.Permissions; // PermissionSetAttribute
...
class Program {
// obtains user token
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
public void DoWorkUnderImpersonation() {
//elevate privileges before doing file copy to handle domain security
WindowsImpersonationContext impersonationContext = null;
IntPtr userHandle = IntPtr.Zero;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
string user = ConfigurationManager.AppSettings["ImpersonationUser"];
string password = ConfigurationManager.AppSettings["ImpersonationPassword"];
try {
Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);
// if domain name was blank, assume local machine
if (domain == "")
domain = System.Environment.MachineName;
// Call LogonUser to get a token for the user
bool loggedOn = LogonUser(user,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref userHandle);
if (!loggedOn) {
Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
return;
}
// Begin impersonating the user
impersonationContext = WindowsIdentity.Impersonate(userHandle);
Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);
//run the program with elevated privileges (like file copying from a domain server)
DoWork();
} catch (Exception ex) {
Console.WriteLine("Exception impersonating user: " + ex.Message);
} finally {
// Clean up
if (impersonationContext != null) {
impersonationContext.Undo();
}
if (userHandle != IntPtr.Zero) {
CloseHandle(userHandle);
}
}
}
private void DoWork() {
//everything in here has elevated privileges
//example access files on a network share through e$
string[] files = System.IO.Directory.GetFiles(#"\\domainserver\e$\images", "*.jpg");
}
}
I was having the same problem. Don't know if you've solved this or not, but what I was really trying to do was access a network share with AD credentials. WNetAddConnection2() is what you need to use in that case.
I have been successfull at impersonating users in another domain, but only with a trust set up between the 2 domains.
var token = IntPtr.Zero;
var result = LogonUser(userID, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
if (result)
{
return WindowsIdentity.Impersonate(token);
}
It's better to use a SecureString:
var password = new SecureString();
var phPassword phPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
IntPtr phUserToken;
LogonUser(username, domain, phPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out phUserToken);
And:
Marshal.ZeroFreeGlobalAllocUnicode(phPassword);
password.Dispose();
Function definition:
private static extern bool LogonUser(
string pszUserName,
string pszDomain,
IntPtr pszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken);
Invalid login/password could be also related to issues in your DNS server - that's what happened to me and cost me good 5 hours of my life. See if you can specify ip address instead on domain name.
The problem I encountered was when my workstation was on one domain, but I needed to authenticate to a server on a different domain:
ERROR: "Exception impersonating user, error code: 1326"
SOLUTION: Added LOGON32_LOGON_NEW_CREDENTIALS as a fallback to Impersonate/LogonUser()
Impersonation.cs
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace TestDBAccess
{
public class Impersonation : IDisposable
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String Username, String Domain, String Password, int LogonType, int LogonProvider, out IntPtr Token);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK = 3;
public const int LOGON32_LOGON_BATCH = 4;
public const int LOGON32_LOGON_SERVICE = 5;
public const int LOGON32_LOGON_UNLOCK = 7;
public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
private WindowsImpersonationContext impersonationContext = null;
private IntPtr userHandle = IntPtr.Zero;
public Impersonation(string user, string domain, string password)
{
// Extract domain/username from user string
string[] principal = user.Split('\\');
if (principal.Length == 2)
{
domain = principal[0];
user = principal[1];
}
if (string.IsNullOrEmpty(domain))
domain = GetDefaultDomain();
// Call LogonUser to get a token for the user
bool loggedOn =
LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, out userHandle);
if (!loggedOn)
{
int ierr = Marshal.GetLastWin32Error();
if (ierr == 1326)
{
loggedOn =
LogonUser(user, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT, out userHandle);
}
if (!loggedOn)
throw new Exception("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
}
// Begin impersonating the user
impersonationContext = WindowsIdentity.Impersonate(userHandle);
}
public static string GetDefaultDomain ()
{
return System.Environment.UserDomainName;
}
public void Dispose()
{
// Clean up
if (impersonationContext != null)
impersonationContext.Undo();
if (userHandle != IntPtr.Zero)
CloseHandle(userHandle);
}
}
}
ExampleClient.cs
Impersonation Impersonation = null;
try
{
Impersonation = new Impersonation(username, null, password);
LogMsg("Attempting to connect to (" + dbInstance.instance + ")...");
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
string sql = edtTestSql.Text;
LogMsg("Attempting to query (" + sql + ")...");
using (SqlCommand command = new SqlCommand(sql, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
LogMsg("next row: " + DumpRow(reader));
}
}
}
}
catch (Exception ex)
{
LogMsg(ex.Message);
}
finally
{
if (Impersonation != null)
Impersonation.Dispose();
}
I want to know, if a WindowsAccount is Password protected.
For security reasons, you cannot get the Password, that’s clear, but there must be a way, to find out, if a Password is set.
public bool IsAccountPasswordProteced(String userName)
{
String entryString = "WinNT://" + Environment.MachineName + ",Computer";
DirectoryEntry dirEntry = new DirectoryEntry(entryString);
DirectoryEntry user = dirEntry.Children.Find(userName, "User");
// First try was to check the ADS_UF_PASSWD_NOTREQD flag.
// If this flag is set, the account has no password,
// but if not, both is possible.
int userFlags = (int)user.Properties["UserFlags"].Value;
return (userFlags & (int)ActiveDs.ADS_USER_FLAG.ADS_UF_PASSWD_NOTREQD) == 0;
// Second try was to check the PasswordAge.
int pwAge = (int)user.Properties["PasswordAge"].Value;
return pwAge > 0;
}
If there is no better way, I will use the LogonUser-function, but that’s not the way I was looking for. But it’s better than nothing.
If I use this from a local account (not via network, because of the LogonType) and for an enabled account, it should work.
I used this two links:
Calling LogonUser
Detect empty Passwords
public bool IsAccountPasswordProtected(String userName)
{
String entryString = "WinNT://" + Environment.MachineName + ",Computer";
DirectoryEntry dirEntry = new DirectoryEntry(entryString);
DirectoryEntry user = dirEntry.Children.Find(userName, "User");
////EDIT: this flag can also be set, if the account has a password
//int userFlags = (int)user.Properties["UserFlags"].Value;
//if ((userFlags & (int)ActiveDs.ADS_USER_FLAG.ADS_UF_PASSWD_NOTREQD) != 0)
// return false;
IntPtr token;
bool result = LogonUser(
user.Name, Environment.UserDomainName,
"",
LogonTypes.Interactive,
LogonProviders.Default,
out token);
if (result)
{
CloseHandle(token);
return false;
}
else
{
int err = Marshal.GetLastWin32Error();
if (err == 1327) // ERROR_ACCOUNT_RESTRICTION
return false;
//if(err == 1331) // ERROR_ACCOUNT_DISABLED
return true;
}
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(
string principal,
string authority,
string password,
LogonTypes logonType,
LogonProviders logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
enum LogonTypes : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
enum LogonProviders : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
If you can get the UPN name or user token for the given account (one of the properties of the user object should tell you), then you should just be able to use the WindowsIdentity class something like this:
using System.Security.Principal;
// ...
var identity = new WindowsIdentity("foo-UPN");
var requiresPassword = identity.AuthenticationType != string.Empty;