Checking Window accounts with blank passwords using LogonUser in .Net

Hi all

Using VB .NET, I am attempting to see if the current user has logged onto the local system with a password using a call to the LogonUser function in the  Lib "advapi32.dll". My code works fine for accounts that have a password ( I test this by creating a local XP account, assign a non-blank passwd and attempt to logon with the user using the aforementioned command). This is confirmed by auditing on logon events in the event viewer.

My issue is that when I create a user with a Blank passwd (i.e no assigned passwd), the LogonUser function with a blank Passwd does not logon successfully and fails. Again, the logon failure is reflected in Event Viewer.

The call syntax I'm using is

Dim returnValue As Boolean = LogonUser(strUserName, strDomainName, BLANKPASSWD, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, tokenHandle)

Why can't I get LogonUser to accept a blank Passwd (3rd field)? Please respond in VB .NET terms.

Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

At the command prompt, type the following:

  net accounts

You will see the minimum allowed password length. You can change this setting to allow blank passwords using the command:

  net accounts /minpwlen:0

I guess this solves your problem.


  Nayer Naguib

Did you try the "Nothing" keyword (meaning NULL) instead of an empty (null) string?

Dim returnValue As Boolean = LogonUser(strUserName, strDomainName, Nothing, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, tokenHandle)
pnicklosAuthor Commented:
Hi guys

I have tried all combinations of NULL I can think of including sending Nothing and String.empty etc. No joy unfortunately. Same applies to the Extended version of this command - LogonUserEx

Sorry Nayer, I can logon manually with a blank password on that account - it is when I attempt to programmatically logon using the ADAVPI32.dll LogonUser that I get this issue. I am not attempting to change user account settings on someones system, I am running a security tool that tests to see that the local user doesn't have a blank password and the only way I can do that, as far as I can gather, is by physically trying to logon, via the LogonUser Api, with a blank passwd. Naturally, I did test that I could logon with a blank password manually.

Any other suggestions ?
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

I know that you can log in manually using a blank password. Still, if you check for the MINPWLEN value, you will see that it is greater than zero (default=6).

I think you *must* change this setting before trying to *programmatically* log in to Windows using a blank password. I suggest that you read the stored value first, change it *just* before calling LogonUser() (to zero), and then changing it back after calling LogonUser().


  Nayer Naguib
The fix to this issue is a bit strange...  you'll have to temporarily modify the registry before running the LogonUser function.

The key to change is HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\limitblankpassworduse  it must be set to 0 before you make the API call, and then reset back to 1 afterwards.
pnicklosAuthor Commented:
Thanks Graye, little bit of a bugger this one is - what you suggested is the reason for the LogonUser to fail on a blank password.

My code does work once the RegKey is changed. Unfortunately this leaves me with another issue, I can't guarantee that the logged on user has Local Admin rights and therefore won't be able to guarantee that I can modify the registry in HKLM back and forth as required.

Nayer - thanks for your input however, one of the first things I did was ensure that all password and logon limitations were removed and MinPwd length was set to 0 thus allowing me to change account passwds to any length. So in all my tests, the MinPwdLen was 0. As mentioned above, Graye has discovered the reason for my dilemna.

Is there any other method for a Logged on user to "test" that his account has a blank password programmatically ?
I'd consider using Windows Management Instrumentation (WMI) to pull data about the local accounts (we are just talking about local accounts, right?)
The field in particular is called "PasswordRequired".   If set to false, then the account has a blank password.

Here is an example to demonstrate the concepts

' Remember to add a Reference to System.Management !!!
Imports System
Imports System.Management
Imports System.Windows.Forms

Namespace WMISample

    Public Class MyWMIQuery

        Public Overloads Shared Function Main() As Integer

                Dim searcher As New ManagementObjectSearcher( _
                    "root\CIMV2", _
                    "SELECT * FROM Win32_UserAccount where Domain='Your_PC_Name_Goes_Here'")

                For Each queryObj As ManagementObject in searcher.Get()

                    Console.WriteLine("Win32_UserAccount instance")
                    Console.WriteLine("AccountType: {0}", queryObj("AccountType"))
                    Console.WriteLine("Caption: {0}", queryObj("Caption"))
                    Console.WriteLine("Description: {0}", queryObj("Description"))
                    Console.WriteLine("Disabled: {0}", queryObj("Disabled"))
                    Console.WriteLine("Domain: {0}", queryObj("Domain"))
                    Console.WriteLine("FullName: {0}", queryObj("FullName"))
                    Console.WriteLine("InstallDate: {0}", queryObj("InstallDate"))
                    Console.WriteLine("LocalAccount: {0}", queryObj("LocalAccount"))
                    Console.WriteLine("Lockout: {0}", queryObj("Lockout"))
                    Console.WriteLine("Name: {0}", queryObj("Name"))
                    Console.WriteLine("PasswordChangeable: {0}", queryObj("PasswordChangeable"))
                    Console.WriteLine("PasswordExpires: {0}", queryObj("PasswordExpires"))
                    Console.WriteLine("PasswordRequired: {0}", queryObj("PasswordRequired"))
                    Console.WriteLine("SID: {0}", queryObj("SID"))
                    Console.WriteLine("SIDType: {0}", queryObj("SIDType"))
                    Console.WriteLine("Status: {0}", queryObj("Status"))
            Catch err As ManagementException
                MessageBox.Show("An error occurred while querying for WMI data: " & err.Message)
            End Try
        End Function
    End Class
End Namespace
As far as I know, the PasswordRequired field shows whether a password is *required* or not. Having a password required implies that a user cannot have a blank password. However, having a password not required does *not* imply that the user's password is blank. It just means that the user can *choose* whether or not to set a password.


  Nayer Naguib
Nayer, I just did a quick test, and you're right...   The PasswordRequired field does NOT detect a null password.

I think this is gonna be practically impossible to do if the current user is not an administrator.   For example, digging into the SAM database would not be a viable option.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
pnicklosAuthor Commented:
Should have mentioned I went through the WMI stuff and have also code around the ADS_UF_PASSWD_NOTREQD in the USERACCOUNTCONTROL cn, which is the AD equivalent of above mentioned WMI control - and unfortunately as you guys have figured out, this only allows a user to select a NULL passwd but doesnt determine whether he has or not.

Just for interest, there is another WMI control - Win32_NetworkLoginProfile that contains FLAGS which is a BIT mask field which, if you do a Binary Anding with Hex 20 (decimal 32) you get the same result as in the Win32_UserAccount instance.

Graye, as you surmised, the SAM database hack won't cut it for me as the users may not be local admins.

As you boys have been really helpful, I'll assign points for this query and open another with the next part.

Sorry Nayer but Graye figured out my initial problem with why the blank doesnt work.

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.