views:

607

answers:

2

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;
}
A: 

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;
Noldorin
I tested the “identity.AuthenticationType” value for two Accounts with "WindowsIdentity.GetCurrent()", one with password and one without and in both cases the value is “NTLM”.“DirectoryEntry user” has also an “AuthenticationType”, but for the accounts I tested, it is always “Secure”.
Fry
+1  A: 

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
}
Fry