/*++

Copyright (c) 1998 Microsoft Corporation

Module Name:

    migpwd.c

Abstract:

    Implements a simple password application that sets a default password
    for each local account created.  This application is placed in the
    RunOnce registry key when the Administrator account is set to auto-logon,
    and at least one other local account was created.

    The list of migrated local accounts is kept in

    HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Win9xUpg\Users

    This app prompts the user for a password, explaining what exactly is going
    on, and then deletes the RunOnce and Users value on exit.


Author:

    Jim Schmidt (jimschm) 18-Mar-1998

Revision History:

    jimschm     06-Jul-1998     Added private stress option

--*/

#include "pch.h"
#include "resource.h"
#include "msg.h"

#include <lm.h>

//
// Constants
//

#define MAX_PASSWORD                64

//
// Globals
//

HINSTANCE g_hInst;
HANDLE g_hHeap;
UINT g_TotalUsers;
BOOL g_AutoPassword = FALSE;
TCHAR g_AutoLogonUser[256];
TCHAR g_AutoLogonPassword[MAX_PASSWORD + 1];

//
// !!! This is for internal use only !!!  It is used for auto stress.
//

#ifdef PRERELEASE

BOOL g_AutoStress = FALSE;
TCHAR g_AutoStressUser[MAX_USER_NAME];
TCHAR g_AutoStressPwd[MAX_PASSWORD];
TCHAR g_AutoStressOffice[32];
TCHAR g_AutoStressDbg[MAX_COMPUTER_NAME];
DWORD g_AutoStressFlags;

#endif


//
// Library prototypes
//

BOOL
WINAPI
MigUtil_Entry (
    HINSTANCE hInstance,
    DWORD dwReason,
    PVOID lpReserved
    );


//
// Local prototypes
//

VOID
pCleanup (
    VOID
    );

BOOL
pIsAdministratorOnly (
    VOID
    );

BOOL
CALLBACK
PasswordProc (
    HWND hdlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    );

BOOL
pIsBlankPasswordAllowed (
    VOID
    );

BOOL
pIsPersonal (
    VOID
    )
{
    static BOOL g_Determined = FALSE;
    static BOOL g_Personal = FALSE;
    OSVERSIONINFOEX osviex;

    //
    // Determine if Personal SKU
    //
    if (!g_Determined) {
        g_Determined = TRUE;
        osviex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
        if (GetVersionEx ((LPOSVERSIONINFO)&osviex)) {
            if (osviex.wProductType == VER_NT_WORKSTATION &&
                (osviex.wSuiteMask & VER_SUITE_PERSONAL)
                ) {
                g_Personal = TRUE;
            }
        }
    }
    return g_Personal;
}


//
// Implementation
//

INT
WINAPI
WinMain (
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    PSTR AnsiCmdLine,
    INT CmdShow
    )

/*++

Routine Description:

  The entry point to migpwd.exe.  All the work is done in a dialog box,
  so no message loop is necessary.

Arguments:

  hInstance     - The instance handle of this EXE
  hPrevInstance - The previous instance handle of this EXE if it is
                  running, or NULL if no other instances exist.
  AnsiCmdLine   - The command line (ANSI version)
  CmdShow       - The ShowWindow command passed by the shell

Return Value:

  Returns -1 if an error occurred, or 0 if the exe completed. The exe
  will automatically terminate with 0 if the migration DLL throws an
  exception.

--*/

{
    UINT Result;
    PCTSTR ArgArray[1];
    TCHAR UserName[MAX_USER_NAME];
    DWORD Size;
    HCURSOR OldCursor;
    INITCOMMONCONTROLSEX init = {sizeof (INITCOMMONCONTROLSEX), 0};
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    TCHAR winDir[MAX_PATH];
    PTSTR oobeBalnPath;
    PTSTR cmdLine;
    BOOL ProcessResult;

#ifdef PRERELEASE
    HKEY Key;
    PCTSTR Data;
#endif

    InitCommonControlsEx (&init);

    g_hInst = hInstance;
    g_hHeap = GetProcessHeap();

    OldCursor = SetCursor (LoadCursor (NULL, IDC_ARROW));

    MigUtil_Entry (hInstance, DLL_PROCESS_ATTACH, NULL);

#ifdef PRERELEASE

    Key = OpenRegKeyStr (S_AUTOSTRESS_KEY);
    if (Key) {
        g_AutoStress = TRUE;

        Data = GetRegValueString (Key, S_AUTOSTRESS_USER);
        if (Data) {
            StringCopy (g_AutoStressUser, Data);
            MemFree (g_hHeap, 0, Data);
        } else {
            g_AutoStress = FALSE;
        }

        Data = GetRegValueString (Key, S_AUTOSTRESS_PASSWORD);
        if (Data) {
            StringCopy (g_AutoStressPwd, Data);
            MemFree (g_hHeap, 0, Data);
        } else {
            g_AutoStress = FALSE;
        }

        Data = GetRegValueString (Key, S_AUTOSTRESS_OFFICE);
        if (Data) {
            StringCopy (g_AutoStressOffice, Data);
            MemFree (g_hHeap, 0, Data);
        } else {
            g_AutoStress = FALSE;
        }

        Data = GetRegValueString (Key, S_AUTOSTRESS_DBG);
        if (Data) {
            StringCopy (g_AutoStressDbg, Data);
            MemFree (g_hHeap, 0, Data);
        } else {
            g_AutoStress = FALSE;
        }

        Data = GetRegValueString (Key, S_AUTOSTRESS_FLAGS);
        if (Data) {
            g_AutoStressFlags = _tcstoul (Data, NULL, 10);
            MemFree (g_hHeap, 0, Data);
        } else {
            g_AutoStress = FALSE;
        }

        CloseRegKey (Key);
    }

#endif

    //
    // Launch oobebaln.exe /init
    //

    ZeroMemory (&si, sizeof (si));
    si.cb = sizeof (si);
    si.dwFlags = STARTF_FORCEOFFFEEDBACK;

    if (!GetWindowsDirectory (winDir, ARRAYSIZE(winDir))) {
        StringCopy (winDir, TEXT("c:\\windows"));
    }

    oobeBalnPath = JoinPaths (winDir, TEXT("system32\\oobe\\oobebaln.exe"));
    cmdLine = JoinText (oobeBalnPath, TEXT(" /init"));

    ProcessResult = CreateProcess (
                        oobeBalnPath,
                        cmdLine,
                        NULL,
                        NULL,
                        FALSE,
                        CREATE_DEFAULT_ERROR_MODE,
                        NULL,
                        NULL,
                        &si,
                        &pi
                        );

    if (ProcessResult) {
        CloseHandle (pi.hThread);
        CloseHandle (pi.hProcess);
    } else {
        LOG ((LOG_ERROR, "Cannot start %s", cmdLine));
    }

    FreePathString (oobeBalnPath);
    FreeText (cmdLine);


    //
    // Set passwords
    //

    if (pIsAdministratorOnly()) {
        DEBUGMSG ((DBG_VERBOSE, "Calling Adminitrator password dialog"));
        Result = DialogBox (
                     hInstance,
                     MAKEINTRESOURCE(IDD_ADMIN_PASSWORD_DLG),
                     NULL,
                     PasswordProc
                     );
    } else {
        DEBUGMSG ((DBG_VERBOSE, "Calling multi user password dialog"));
        Result = DialogBox (
                     hInstance,
                     MAKEINTRESOURCE(IDD_PASSWORD_DLG),
                     NULL,
                     PasswordProc
                     );
    }

    if (Result == IDOK) {
        Size = MAX_USER_NAME;
        GetUserName (UserName, &Size);
        ArgArray[0] = UserName;

        pCleanup();

#ifdef PRERELEASE
        if (!g_AutoStress) {
#endif

        //if (g_TotalUsers) {
        //    ResourceMessageBox (NULL, MSG_YOU_ARE_ADMIN, MB_ICONINFORMATION|MB_OK, ArgArray);
        //}

#ifdef PRERELEASE
        } else {
            NETRESOURCE nr;
            LONG rc;
            TCHAR CmdLine[MAX_TCHAR_PATH];
            STARTUPINFO si;
            PROCESS_INFORMATION pi;
            PTSTR UserName;
            TCHAR StressCmdLine[MAX_TCHAR_PATH];
            TCHAR NtDevDomain[MAX_COMPUTER_NAME];
            TCHAR Msg[1024];

            //
            // Autostress: Create connection to \\ntstress or \\ntstress2
            //             Turn on autologon
            //             Create Run key for stress
            //             Run munge /p
            //

            nr.dwType = RESOURCETYPE_ANY;
            nr.lpLocalName = TEXT("s:");
            nr.lpRemoteName = TEXT("\\\\ntstress\\stress");
            nr.lpProvider = NULL;

            rc = WNetAddConnection2 (&nr, g_AutoStressPwd, g_AutoStressUser, 0);

            if (rc != ERROR_SUCCESS) {
                nr.lpRemoteName = TEXT("\\\\ntstress2\\stress");
                rc = WNetAddConnection2 (&nr, g_AutoStressPwd, g_AutoStressUser, 0);
            }

            if (rc == ERROR_SUCCESS) {
                // Prepare command line
                StringCopy (NtDevDomain, g_AutoStressUser);
                UserName = _tcschr (NtDevDomain, TEXT('\\'));
                if (UserName) {
                    *UserName = 0;
                    UserName++;
                } else {
                    UserName = g_AutoStressUser;
                    StringCopy (NtDevDomain, TEXT("ntdev"));
                }

                wsprintf (
                    StressCmdLine,
                    TEXT("%s\\stress.cmd /o %s /n %s /d c:\\stress /k %s /g"),
                    nr.lpRemoteName,
                    g_AutoStressOffice,
                    UserName,
                    g_AutoStressDbg
                    );

                if (g_AutoStressFlags & AUTOSTRESS_PRIVATE) {
                    StringCat (StressCmdLine, TEXT(" /P"));
                }

                if (g_AutoStressFlags & AUTOSTRESS_MANUAL_TESTS) {
                    StringCat (StressCmdLine, TEXT(" /M"));
                }

                // Turn on autologon
                Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
                MYASSERT (Key);

                RegSetValueEx (
                    Key,
                    S_AUTOADMIN_LOGON_VALUE,
                    0,
                    REG_SZ,
                    (PBYTE) TEXT("1"),
                    sizeof (TCHAR) * 2
                    );

                RegSetValueEx (
                    Key,
                    S_DEFAULT_USER_NAME_VALUE,
                    0,
                    REG_SZ,
                    (PBYTE) UserName,
                    SizeOfString (UserName)
                    );

                RegSetValueEx (
                    Key,
                    S_DEFAULT_PASSWORD_VALUE,
                    0,
                    REG_SZ,
                    (PBYTE) g_AutoStressPwd,
                    SizeOfString (g_AutoStressPwd)
                    );

                RegSetValueEx (
                    Key,
                    S_DEFAULT_DOMAIN_NAME_VALUE,
                    0,
                    REG_SZ,
                    (PBYTE) NtDevDomain,
                    SizeOfString (NtDevDomain)
                    );

                CloseRegKey (Key);

                // Prepare the launch of stress
                Key = OpenRegKeyStr (S_RUN_KEY);
                MYASSERT (Key);

                RegSetValueEx (
                    Key,
                    TEXT("Stress"),
                    0,
                    REG_SZ,
                    (PBYTE) StressCmdLine,
                    SizeOfString (StressCmdLine)
                    );

                CloseRegKey (Key);

                // Run munge /p /q /y (to set preferred stress settings and reboot)
                wsprintf (CmdLine, TEXT("%s\\munge.bat /p /q /y"), nr.lpRemoteName);
                ZeroMemory (&si, sizeof (si));
                si.cb = sizeof (si);

                if (!CreateProcess (
                        NULL,
                        CmdLine,
                        NULL,
                        NULL,
                        FALSE,
                        0,
                        NULL,
                        NULL,
                        &si,
                        &pi
                        )) {
                    wsprintf (Msg, TEXT("Can't start %s.  rc=%u"), CmdLine, GetLastError());
                    MessageBox (NULL, Msg, NULL, MB_OK);

                }

            } else {
                wsprintf (Msg, TEXT("Can't connect to ntstress or ntstress2.  rc=%u"), GetLastError());
                MessageBox (NULL, Msg, NULL, MB_OK);
            }
        }
#endif
    }

    MigUtil_Entry (hInstance, DLL_PROCESS_DETACH, NULL);
    SetCursor (OldCursor);

    return 0;
}


VOID
pCopyRegString (
    IN      HKEY DestKey,
    IN      HKEY SrcKey,
    IN      PCTSTR SrcValue
    )

/*++

Routine Description:

  pCopyRegString copies a REG_SZ value from one key to another.  If the value
  does not exist or is not a REG_SZ, nothing is copied.

Arguments:

  DestKey  - Specifies the destination key handle
  SrcKey   - Specifies the source key handle
  SrcValue - Specifies the value in SrcKey to copy

Return Value:

  None.

--*/

{
    PCTSTR Data;

    Data = GetRegValueString (SrcKey, SrcValue);
    if (Data) {
        RegSetValueEx (
            DestKey,
            SrcValue,
            0,
            REG_SZ,
            (PBYTE) Data,
            SizeOfString (Data)
            );

        MemFree (g_hHeap, 0, Data);
    }
}


VOID
pCleanup (
    VOID
    )

/*++

Routine Description:

  pCleanup performs all cleanup necessary to remove auto-logon and migpwd.exe.

Arguments:

  None.

Return Value:

  None.

--*/

{
    HKEY Key;
    HKEY DestKey;
    TCHAR ExeName[MAX_PATH];

    //
    // This is the place where we will delete the Run or RunOnce entry,
    // remove the Setup\Win9xUpg\Users key, remove the auto logon,
    // and delete this EXE.
    //

    Key = OpenRegKeyStr (S_RUNONCE_KEY);
    if (Key) {
        RegDeleteValue (Key, S_MIGPWD);
        CloseRegKey (Key);
    }

    Key = OpenRegKeyStr (S_RUN_KEY);
    if (Key) {
        RegDeleteValue (Key, S_MIGPWD);
        CloseRegKey (Key);
    }

    Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
    if (Key) {
        RegDeleteValue (Key, S_AUTOADMIN_LOGON_VALUE);
        RegDeleteValue (Key, S_DEFAULT_PASSWORD_VALUE);
        CloseRegKey (Key);
    }

    Key = OpenRegKeyStr (S_WIN9XUPG_KEY);
    if (Key) {
        RegDeleteKey (Key, S_USERS_SUBKEY);
        CloseRegKey (Key);
    }

    GetModuleFileName (NULL, ExeName, MAX_PATH);
    MoveFileEx (ExeName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);

    //
    // Transfer auto logon from Win9xUpg
    //

    Key = OpenRegKeyStr (S_WIN9XUPG_KEY);

    if (Key) {
        DestKey = OpenRegKeyStr (S_WINLOGON_REGKEY);

        if (DestKey) {
            pCopyRegString (DestKey, Key, S_AUTOADMIN_LOGON_VALUE);

            if (g_AutoLogonUser[0]) {
                //
                // We changed the password for this user
                //

                RegSetValueEx (
                    DestKey,
                    S_DEFAULT_PASSWORD_VALUE,
                    0,
                    REG_SZ,
                    (PBYTE) g_AutoLogonPassword,
                    SizeOfString (g_AutoLogonPassword)
                    );
            } else {
                pCopyRegString (DestKey, Key, S_DEFAULT_PASSWORD_VALUE);
            }

            pCopyRegString (DestKey, Key, S_DEFAULT_USER_NAME_VALUE);
            pCopyRegString (DestKey, Key, S_DEFAULT_DOMAIN_NAME_VALUE);

            CloseRegKey (DestKey);
        }

        CloseRegKey (Key);
    }
}


BOOL
pSetUserPassword (
    IN      PCTSTR User,
    IN      PCTSTR Password
    )

/*++

Routine Description:

  pSetUserPassword changes the password on the specified user account.

Arguments:

  User     - Specifies the user name to change
  Password - Specifies the new password

Return Value:

  TRUE if the password was changed, or FALSE if an error occurred.

--*/

{
    LONG rc;
    PCWSTR UnicodeUser;
    PCWSTR UnicodePassword;
    PUSER_INFO_1 ui1;

    UnicodeUser     = CreateUnicode (User);
    UnicodePassword = CreateUnicode (Password);

    rc = NetUserGetInfo (NULL, (PWSTR) UnicodeUser, 1, (PBYTE *) (&ui1));

    if (rc != NO_ERROR) {
        SetLastError (rc);
        DEBUGMSG ((DBG_ERROR, "User %s does not exist", User));
        rc = NO_ERROR;
    } else {

        ui1->usri1_password = (PWSTR) UnicodePassword;

        rc = NetUserSetInfo (NULL, (PWSTR) UnicodeUser, 1, (PBYTE) ui1, NULL);

        NetApiBufferFree ((PVOID) ui1);

    }

    DestroyUnicode (UnicodeUser);
    DestroyUnicode (UnicodePassword);

    DEBUGMSG_IF ((rc != NO_ERROR, DBG_ERROR, "Password could not be set, rc=%u", rc));

    SetLastError (rc);
    return rc == NO_ERROR;
}


BOOL
CALLBACK
PasswordProc (
    HWND hdlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    )

/*++

Routine Description:

  PasswordProc is the dialog procedure for the password dialog.  It
  initializes the list box with the names of all new accounts.  When the user
  choses Change, the password is tested and changed if possible.  A popup is
  presented if the user tries to enter a blank password.

Arguments:

  hdlg   - Dialog window handle
  uMsg   - Message to process
  wParam - Message-specific
  lParam - Message-specific

Return Value:

  TRUE if the message was processed, or FALSE if the message should be
  processed by the OS.

--*/

{
    HKEY Key;
    HKEY win9xUpgKey;
    static HWND List;
    REGVALUE_ENUM e;
    PCTSTR Data;
    //LONG Index;
    //LONG Count;
    TCHAR Pwd[MAX_PASSWORD + 1];
    TCHAR ConfirmPwd[MAX_PASSWORD + 1];
    static HWND Edit1, Edit2;
    GROWBUFFER Line = GROWBUF_INIT;
    BOOL b;
    SIZE Size;
    INT MaxWidth;
    INT IntegralWidth;
    TEXTMETRIC tm;
    HDC dc;
    RECT rect;
    DWORD bufSize;
    TCHAR computerName[MAX_PATH];
    PCTSTR domainName;
    BOOL changingAutoLogonPwd;

    *Pwd = 0;
    *ConfirmPwd = 0;

    switch (uMsg) {

    case WM_INITDIALOG:

        //
        // Enable a timer so the dialog never goes to sleep
        // and we ensure it's always the foreground window
        //

        SetTimer (hdlg, 1, 30000, NULL);
        SetTimer (hdlg, 2, 1000, NULL);

        //
        // Fill list box with user names from registry
        //

        List = GetDlgItem (hdlg, IDC_USER_LIST);
        Edit1 = GetDlgItem (hdlg, IDC_PASSWORD);
        Edit2 = GetDlgItem (hdlg, IDC_CONFIRM);

        SendMessage (Edit1, EM_LIMITTEXT, MAX_PASSWORD, 0);
        SendMessage (Edit2, EM_LIMITTEXT, MAX_PASSWORD, 0);

        g_TotalUsers = 0;

        if (List) {
            //
            // Compute text metrics for list
            //

            dc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);

            SelectObject (dc, (HFONT) SendMessage (List, WM_GETFONT, 0, 0));
            GetTextMetrics (dc, &tm);

            Key = OpenRegKeyStr (S_USER_LIST_KEY);
            if (Key) {
                //
                // Enumerate the users in this key.  Data is saved with
                // each list entry, though it is not currently used.
                //

                MaxWidth = 0;

                if (EnumFirstRegValue (&e, Key)) {
                    do {
                        Data = GetRegValueString (e.KeyHandle, e.ValueName);
                        if (Data) {

                            GetTextExtentPoint (
                                dc,
                                e.ValueName,
                                TcharCount (e.ValueName),
                                &Size
                                );

                            MaxWidth = max (MaxWidth, Size.cx);

                            if (g_TotalUsers) {
                                GrowBufAppendString (&Line, TEXT("\t"));
                            }

                            GrowBufAppendString (&Line, e.ValueName);
                            g_TotalUsers++;

                            MemFree (g_hHeap, 0, Data); // edit ctrl version

                            //
                            // List box code:
                            //
                            //
                            //Index = SendMessage (
                            //            List,
                            //            LB_ADDSTRING,
                            //            0,
                            //            (LPARAM) e.ValueName
                            //            );
                            //
                            //MYASSERT (Index != LB_ERR);
                            //SendMessage (
                            //    List,
                            //    LB_SETITEMDATA,
                            //    Index,
                            //    (LPARAM) Data
                            //    );
                            //
                            // free Data later
                        }

                    } while (EnumNextRegValue (&e));
                }

                GrowBufAppendString (&Line, TEXT("\r\n"));
                SetWindowText (List, (PCTSTR) Line.Buf);

                MaxWidth += tm.tmAveCharWidth * 2;

                GetWindowRect (List, &rect);

                IntegralWidth = (rect.right - rect.left) / MaxWidth;
                IntegralWidth = max (IntegralWidth, 1);

                MaxWidth = IntegralWidth * (rect.right - rect.left);

                rect.left = 0;
                rect.right = 100;
                rect.top = 0;
                rect.bottom = 100;

                MapDialogRect (hdlg, &rect);

                MaxWidth = (MaxWidth * 100) / (rect.right - rect.left);

                SendMessage (List, EM_SETTABSTOPS, 1, (LPARAM) (&MaxWidth));

                CloseRegKey (Key);
                DeleteDC (dc);
            }
            ELSE_DEBUGMSG ((DBG_WARNING, "%s not found", S_USER_LIST_KEY));

            FreeGrowBuffer (&Line);

            if (!g_TotalUsers) {
                EndDialog (hdlg, IDOK);
            } else {
                SetForegroundWindow (hdlg);
            }
        }

        if (pIsPersonal ()) {
            g_AutoPassword = TRUE;
            PostMessage (hdlg, WM_COMMAND, IDOK, 0);
        }
#ifdef PRERELEASE
        //
        // !!! This is for internal use only !!!  It is used for auto stress.
        //

        else if (g_AutoStress) {
            PostMessage (hdlg, WM_COMMAND, IDOK, 0);
        }
#endif

        return FALSE;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDOK:
            if (pIsPersonal () && g_AutoPassword) {
                StringCopy (Pwd, TEXT(""));
                StringCopy (ConfirmPwd, Pwd);
            } else {
                GetWindowText (Edit1, Pwd, MAX_PASSWORD + 1);
                GetWindowText (Edit2, ConfirmPwd, MAX_PASSWORD + 1);
                if (lstrcmp (Pwd, ConfirmPwd)) {
                    OkBox (hdlg, MSG_PASSWORDS_DO_NOT_MATCH);
                    SetWindowText (Edit1, S_EMPTY);
                    SetWindowText (Edit2, S_EMPTY);
                    SetFocus (Edit1);
                    break;
                }
#ifdef PRERELEASE
                //
                // !!! This is for internal use only !!!  It is used for auto stress.
                //

                if (g_AutoStress) {
                    StringCopy (Pwd, TEXT("Password1"));
                    StringCopy (ConfirmPwd, Pwd);
                }
#endif

                if (*Pwd == 0) {
                    if (pIsBlankPasswordAllowed()) {
                        //
                        // Don't warn about blank passwords, since on Whistler they
                        // are safe.
                        //
                        //if (IDYES != YesNoBox (hdlg, MSG_EMPTY_PASSWORD_WARNING)) {
                        //    break;
                        //}
                    } else {
                        OkBox (hdlg, MSG_MUST_SPECIFY_PASSWORD);
                        break;
                    }
                }
            }

            //
            // Enumerate all the users and set the password on each
            //

            b = TRUE;
            Key = OpenRegKeyStr (S_USER_LIST_KEY);
            if (Key) {
                //
                // Get the user name & pwd of the autologon (if any)
                //

                g_AutoLogonUser[0] = 0;
                g_AutoLogonPassword[0] = 0;

                bufSize = ARRAYSIZE (computerName);
                if (GetComputerName (computerName, &bufSize)) {
                    win9xUpgKey = OpenRegKeyStr (S_WIN9XUPG_KEY);

                    if (win9xUpgKey) {

                        domainName = GetRegValueString (win9xUpgKey, S_DEFAULT_DOMAIN_NAME_VALUE);
                        if (domainName) {
                            if (StringIMatch (computerName, domainName)) {

                                //
                                // Process local accounts only
                                //

                                Data = GetRegValueString (win9xUpgKey, S_DEFAULT_USER_NAME_VALUE);
                                if (Data) {
                                    StringCopyByteCount (g_AutoLogonUser, Data, sizeof(g_AutoLogonUser));
                                    MemFree (g_hHeap, 0, Data);
                                }
                            }
                            ELSE_DEBUGMSG ((DBG_VERBOSE, "Autologon set for non-local user (domain is %s)", domainName));

                            MemFree (g_hHeap, 0, domainName);
                        }

                        CloseRegKey (win9xUpgKey);
                    }
                }

                //
                // Enumerate the users in this key
                //

                changingAutoLogonPwd = FALSE;

                if (EnumFirstRegValue (&e, Key)) {
                    do {

                        if (g_AutoLogonUser[0]) {
                            if (!changingAutoLogonPwd && StringIMatch (e.ValueName, g_AutoLogonUser)) {
                                changingAutoLogonPwd = TRUE;
                                StringCopy (g_AutoLogonPassword, Pwd);
                            }
                        }

                        if (!pSetUserPassword (e.ValueName, Pwd)) {
                            if (!g_AutoPassword) {
                                if (GetLastError() == NERR_PasswordTooShort) {
                                    OkBox (hdlg, MSG_PASSWORD_TOO_SHORT);
                                } else {
                                    OkBox (hdlg, MSG_PASSWORD_INVALID);
                                }
                            }

                            b = FALSE;
                            g_AutoPassword = FALSE;
                            break;
                        }

                    } while (EnumNextRegValue (&e));
                }

                //
                // NOTE: b might be FALSE; changingAutoLogonPwd only matters
                // when b is TRUE, because we just stay in the dialog until
                // then.
                //

                if (b && !changingAutoLogonPwd) {
                    g_AutoLogonUser[0] = 0;
                }

                CloseRegKey (Key);
            }

            if (b) {
                EndDialog (hdlg, LOWORD (wParam));
            }

            break;
        }
        break;

    case WM_TIMER:
        if (wParam == 2) {
            //
            //  This timer ensures we have the keyboard focus
            //  even if another process tries to take it while
            //  the dialog is being shown.
            //
            if (GetForegroundWindow () != hdlg) {
                SetForegroundWindow (hdlg);
            }
        } else {
            //
            // Make this thread a no-sleep thread
            //
            SetThreadExecutionState (ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS);
        }
        break;

    case WM_DESTROY:

        KillTimer (hdlg, 1);
        KillTimer (hdlg, 2);

        //List = GetDlgItem (hdlg, IDC_LIST);
        //if (List) {
        //
        //    Count = SendMessage (List, LB_GETCOUNT, 0, 0);
        //    for (Index = 0 ; Index < Count ; Index++) {
        //        Data = (PCTSTR) SendMessage (List, LB_GETITEMDATA, Index, 0);
        //        if (Data) {
        //            MemFree (g_hHeap, 0, Data);
        //        }
        //    }
        //}

        break;

    }


    return FALSE;
}


BOOL
pIsAdministratorOnly (
    VOID
    )
{
    BOOL NonAdminExists = FALSE;
    PCTSTR AdministratorName;
    HKEY Key;
    REGVALUE_ENUM e;
    PCTSTR Data;
    BOOL AdministratorExists = FALSE;

    AdministratorName = GetStringResource (MSG_ADMINISTRATOR);
    MYASSERT (AdministratorName);

    Key = OpenRegKeyStr (S_USER_LIST_KEY);
    if (Key) {
        //
        // Enumerate the users in this key.  Data is saved with
        // each list entry, though it is not currently used.
        //

        if (EnumFirstRegValue (&e, Key)) {
            do {
                Data = GetRegValueString (e.KeyHandle, e.ValueName);
                if (Data) {
                    if (!StringIMatch (e.ValueName, AdministratorName)) {
                        NonAdminExists = TRUE;
                    } else {
                        AdministratorExists = TRUE;
                    }

                    MemFree (g_hHeap, 0, Data);
                }

            } while (EnumNextRegValue (&e));
        }

        CloseRegKey (Key);
    }
    ELSE_DEBUGMSG ((DBG_WARNING, "%s not found", S_USER_LIST_KEY));

    FreeStringResource (AdministratorName);

    return !NonAdminExists && AdministratorExists;
}



BOOL
pIsBlankPasswordAllowed (
    VOID
    )
{
    PUSER_MODALS_INFO_0 umi;
    NET_API_STATUS rc;
    BOOL b;

    rc = NetUserModalsGet (
            NULL,
            0,
            (PBYTE *) &umi
            );

    if (rc != ERROR_SUCCESS) {
        SetLastError(rc);
        DEBUGMSG ((DBG_ERROR, "Can't get password policy info"));
        return TRUE;
    }

    b = (umi->usrmod0_min_passwd_len == 0);

    NetApiBufferFree ((PVOID) umi);

    return b;
}