mslunp.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 18k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include "resource.h"
  4. #include <winnetwk.h>
  5. #include <netspi.h>
  6. #pragma data_seg(".shared")
  7. char szDefaultLogonUsername[MAX_PATH] = "";
  8. char szDefaultLogonPassword[MAX_PATH] = "";
  9. BOOL fDoDefaultLogon = FALSE;
  10. #pragma data_seg()
  11. struct LogonData
  12. {
  13.     LPLOGONINFO lpAuthentInfo;
  14.     DWORD dwFlags;
  15.     IUser **ppOut;
  16.     HBITMAP hbmTransparent;
  17. };
  18. void ObfuscateString(LPSTR pszBuffer)
  19. {
  20.     DWORD dwMask = 0xa95e633b;      /* nice random collection of bits */
  21.     unsigned char ch;
  22.     do {
  23.         ch = *pszBuffer;
  24.         *(pszBuffer++) = ch ^ (unsigned char)(dwMask & 0xff);
  25.         dwMask = (dwMask >> 8) | (dwMask << 24);
  26.     } while (ch);
  27. }
  28. void DeObfuscateString(LPSTR pszBuffer)
  29. {
  30.     DWORD dwMask = 0xa95e633b;      /* nice random collection of bits */
  31.     unsigned char ch;
  32.     do {
  33.         ch = *pszBuffer ^ (unsigned char)(dwMask & 0xff);
  34.         *(pszBuffer++) = ch;
  35.         dwMask = (dwMask >> 8) | (dwMask << 24);
  36.     } while (ch);
  37. }
  38. void CacheLogonCredentials(LPCSTR pszUsername, LPCSTR pszPassword)
  39. {
  40.     lstrcpy(szDefaultLogonUsername, pszUsername);
  41.     lstrcpy(szDefaultLogonPassword, pszPassword);
  42.     fDoDefaultLogon = TRUE;
  43.     ObfuscateString(szDefaultLogonUsername);
  44.     ObfuscateString(szDefaultLogonPassword);
  45. }
  46. SPIENTRY NPGetCaps(
  47.     DWORD nIndex
  48.     )
  49. {
  50.     switch (nIndex) {
  51.     case WNNC_SPEC_VERSION:
  52.         return 0x00040001;          /* spec version 4.1 */
  53.     case WNNC_NET_TYPE:
  54.         return WNNC_NET_MSNET;
  55.     case WNNC_DRIVER_VERSION:
  56.         return 0x00010000;          /* BUGBUG - driver version 1.0 */
  57.     case WNNC_USER:
  58.         return
  59. //          WNNC_USR_GETUSER |
  60.             0;
  61.     case WNNC_CONNECTION:
  62.         return
  63.             0;
  64.     case WNNC_DIALOG:
  65.         return
  66.             0;
  67.     case WNNC_ENUMERATION:
  68.         return
  69.             0;
  70.     case WNNC_START:
  71.         return 0x1;                 /* started */
  72.     case WNNC_RESOURCE:
  73.         return
  74.             0;
  75.     case WNNC_AUTHENTICATION:
  76.         return
  77.             WNNC_AUTH_LOGON |
  78.             WNNC_AUTH_LOGOFF |
  79. //          WNNC_AUTH_GETHOMEDIRECTORY |
  80. //          WNNC_AUTH_GETPOLICYPATH |
  81.             0;
  82.     }
  83.     return 0;
  84. }
  85. VOID PlaceDialog(HWND hDlg, BOOL fTopThird)
  86. {
  87.     RECT rc;
  88.     int dyScreen = GetSystemMetrics(SM_CYSCREEN);
  89.     int yDialog;
  90.     GetWindowRect(hDlg,&rc);
  91.     if (fTopThird)
  92.         yDialog = (dyScreen / 3) - ((rc.bottom-rc.top) / 2);
  93.     else
  94.         yDialog = (dyScreen - (rc.bottom - rc.top)) / 2;
  95.     SetWindowPos(hDlg,NULL,
  96.                (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
  97.                yDialog, 0, 0, SWP_NOSIZE);
  98. }
  99. void UserSelected(HWND hwndLB, int iItem)
  100. {
  101.     BOOL fNeedPassword;
  102.     BOOL fEnableOK;
  103.     if (iItem == LB_ERR) {
  104.         fNeedPassword = FALSE;
  105.         fEnableOK = FALSE;
  106.     }
  107.     else {
  108.         IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
  109.         fNeedPassword = FAILED(pUser->Authenticate(""));
  110.         fEnableOK = TRUE;
  111.     }
  112.     HWND hDlg = GetParent(hwndLB);
  113.     EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD_LABEL), fNeedPassword);
  114.     EnableWindow(GetDlgItem(hDlg, IDC_PASSWORD), fNeedPassword);
  115.     EnableWindow(GetDlgItem(hDlg, IDOK), fEnableOK);
  116. }
  117. HRESULT FillUserList(HWND hwndLB, IUserDatabase *pDB, LPCSTR pszDefaultSelection,
  118.                      BOOL fIncludeGuest, PFNSELNOTIFY pfnSelNotify)
  119. {
  120.     IEnumUnknown *pEnum;
  121.     BOOL fSelectionSet = FALSE;
  122.     if (fIncludeGuest) {
  123.         NLS_STR nlsTemp(MAX_RES_STR_LEN);
  124.         if (nlsTemp.LoadString(IDS_GUEST_USERNAME) == ERROR_SUCCESS) {
  125.             UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)nlsTemp.QueryPch());
  126.             if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
  127.                 ::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
  128.             }
  129.         }
  130.     }
  131.     HRESULT hres = pDB->EnumUsers(&pEnum);
  132.     if (SUCCEEDED(hres)) {
  133.         IUnknown *pUnk;
  134.         while (pEnum->Next(1, &pUnk, NULL) == S_OK) {
  135.             IUser *pUser;
  136.             if (SUCCEEDED(pUnk->QueryInterface(IID_IUser, (void **)&pUser))) {
  137.                 char szBuf[cchMaxUsername+1];
  138.                 DWORD cbBuffer = sizeof(szBuf);
  139.                 if (SUCCEEDED(pUser->GetName(szBuf, &cbBuffer))) {
  140.                     UINT iItem = (UINT)::SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuf);
  141.                     if (iItem != LB_ERR && iItem != LB_ERRSPACE) {
  142.                         if (::SendMessage(hwndLB, LB_SETITEMDATA, iItem, (LPARAM)pUser) == LB_ERR)
  143.                             ::SendMessage(hwndLB, LB_SETITEMDATA, iItem, 0);
  144.                         if (!fSelectionSet) {
  145.                             if (pszDefaultSelection != NULL && !::stricmpf(szBuf, pszDefaultSelection)) {
  146.                                 fSelectionSet = TRUE;
  147.                                 ::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
  148.                                 if (pfnSelNotify != NULL)
  149.                                     (*pfnSelNotify)(hwndLB, iItem);
  150.                             }
  151.                         }
  152.                     }
  153.                 }
  154.                 /* Note that pUser is not Release()d here, since the
  155.                  * listbox has a pointer to it.
  156.                  */
  157.             }
  158.             pUnk->Release();
  159.         }
  160.         if (!fSelectionSet) {
  161.             if (pfnSelNotify)
  162.                 (*pfnSelNotify)(hwndLB, LB_ERR);
  163.         }
  164.         else {
  165.             /* If we select the default item above, then insert more names
  166.              * above it, the focus rect and the selection will be different,
  167.              * which is confusing if the user tabs to the listbox.  Work
  168.              * around this by setting the caret index manually.
  169.              */
  170.             DWORD iItem = ::SendMessage(hwndLB, LB_GETCURSEL, 0, 0);
  171.             if (iItem != LB_ERR)
  172.                 ::SendMessage(hwndLB, LB_SETCURSEL, iItem, 0);
  173.         }
  174.         pEnum->Release();
  175.     }
  176.     if (FAILED(hres))
  177.         return hres;
  178.     return fSelectionSet ? NOERROR : S_FALSE;
  179. }
  180. BOOL IsMemphis(void)
  181. {
  182.     OSVERSIONINFOA osvi;
  183.     osvi.dwOSVersionInfoSize = sizeof(osvi);
  184.     GetVersionExA(&osvi);
  185.     return (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId &&
  186.             (osvi.dwMajorVersion > 4 || 
  187.              (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion >= 10)));
  188. }
  189. DWORD InitLogonDialog(HWND hwndDialog, LogonData *pld)
  190. {
  191.     DWORD err = WN_NO_NETWORK;
  192.     BOOL fSelectionSet = FALSE;
  193.     ::SetWindowLongPtr(hwndDialog, DWL_USER, (DWORD)pld);
  194.     PlaceDialog(hwndDialog, FALSE);
  195.     int idBitmap;
  196.     DWORD dwFlags;
  197.     if (IsMemphis())
  198.         idBitmap = IDB_IMAGE_WIN98_LOGON;
  199.     else
  200.         idBitmap = IDB_IMAGE_LOGON;
  201.     /* The bitmap we show at the top of the logon dialog has black text on a
  202.      * transparent background.  If the dialog background is very dark, the
  203.      * text will be unreadable.  In that case we use a static bitmap with
  204.      * a white background.  For more common background colors, though, we use
  205.      * LoadImage to load a transparent image and replace the bitmap in the
  206.      * dialog.
  207.      *
  208.      * CODEWORK: Could try a variant of COLORISLIGHT macro from shell32,
  209.      * defview.cpp;  it seems pretty aggressive about declaring blues in
  210.      * particular as "dark".  Maybe we could have the alternate bitmap be
  211.      * 3D-mapped as well, but have white text and maybe a white box around
  212.      * the Windows flag, then we could always be transparent and just choose
  213.      * one or the other at an arbitrary cutoff point.
  214.      */
  215.     DWORD clrBtnFace = GetSysColor(COLOR_3DFACE);
  216.     if ((LOBYTE(clrBtnFace) >= 128) ||
  217.         (LOBYTE(clrBtnFace >> 8) >= 128) ||
  218.         (LOBYTE(clrBtnFace >> 16) >= 128)) {
  219.         dwFlags = LR_LOADMAP3DCOLORS;       /* we'll use a transparent bitmap */
  220.     }
  221.     else {
  222.         idBitmap++;             /* advance to static bitmap ID */
  223.         dwFlags = LR_DEFAULTCOLOR;
  224.     }
  225.     pld->hbmTransparent = (HBITMAP)LoadImage(::hInstance,
  226.                                         MAKEINTRESOURCE(idBitmap),
  227.                                         IMAGE_BITMAP, 0, 0,
  228.                                         dwFlags);
  229.     if (pld->hbmTransparent != NULL) {
  230.         HBITMAP hbmOld = (HBITMAP)SendDlgItemMessage(hwndDialog,
  231.                                                      IDC_MAIN_CAPTION,
  232.                                                      STM_SETIMAGE,
  233.                                                      (WPARAM)IMAGE_BITMAP,
  234.                                                      (LPARAM)pld->hbmTransparent);
  235.         /* If we set the new bitmap into the control, we got the old one
  236.          * back.  Delete the old one.  We will also have to delete the
  237.          * new one when the dialog is dismissed.
  238.          */
  239.         if (hbmOld != NULL)
  240.             DeleteObject(hbmOld);
  241.     }
  242.     IUserDatabase *pDB;
  243.     if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  244.         HRESULT hres = FillUserList(GetDlgItem(hwndDialog, IDC_USERNAME),
  245.                                     pDB, pld->lpAuthentInfo ? pld->lpAuthentInfo->lpUsername : NULL,
  246.                                     FALSE, UserSelected);
  247.         if (SUCCEEDED(hres)) {
  248.             err = ERROR_SUCCESS;
  249.             ::SetFocus(::GetDlgItem(hwndDialog, hres == NOERROR ? IDC_PASSWORD : IDC_USERNAME));
  250.         }
  251.         pDB->Release();
  252.     }
  253.     return err;
  254. }
  255. BOOL ValidateLogonDialog(HWND hwndDialog)
  256. {
  257.     DWORD iItem = ::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  258.     if (iItem == LB_ERR)
  259.         return FALSE;
  260.     IUser *pUser = (IUser *)::SendDlgItemMessage(hwndDialog, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  261.     if (pUser != NULL) {
  262.         NLS_STR nlsUsername(cchMaxUsername+1);
  263.         if (nlsUsername.QueryError())
  264.             return FALSE;
  265.         DWORD cbBuffer = nlsUsername.QueryAllocSize();
  266.         pUser->GetName(nlsUsername.Party(), &cbBuffer);
  267.         nlsUsername.DonePartying();
  268.         HWND hwndPassword = ::GetDlgItem(hwndDialog, IDC_PASSWORD);
  269.         NLS_STR nlsPassword(::GetWindowTextLength(hwndPassword)+2);
  270.         if (nlsPassword.QueryError())
  271.             return FALSE;
  272.         ::GetWindowText(hwndPassword, nlsPassword.Party(), nlsPassword.QueryAllocSize()-1);
  273.         nlsPassword.DonePartying();
  274.         if (SUCCEEDED(pUser->Authenticate(nlsPassword.QueryPch()))) {
  275.             LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWL_USER);
  276.             if (pld->lpAuthentInfo) {
  277.                 DWORD cbUsername = pld->lpAuthentInfo->cbUsername;
  278.                 DWORD cbPassword = pld->lpAuthentInfo->cbPassword;
  279.                 NPSCopyNLS(&nlsUsername, pld->lpAuthentInfo->lpUsername, &cbUsername);
  280.                 NPSCopyNLS(&nlsPassword, pld->lpAuthentInfo->lpPassword, &cbPassword);
  281.             }
  282.             if (pld->ppOut) {
  283.                 *pld->ppOut = pUser;
  284.                 pUser->AddRef();
  285.             }
  286.             if (pld->dwFlags & LUA_FORNEXTLOGON) {
  287.                 CacheLogonCredentials(nlsUsername.QueryPch(), nlsPassword.QueryPch());
  288.             }
  289.             return TRUE;
  290.         }
  291.         NLS_STR nlsTitle(MAX_RES_STR_LEN);
  292.         NLS_STR nlsMessage(MAX_RES_STR_LEN);
  293.         if (!nlsTitle.QueryError() && !nlsMessage.QueryError()) {
  294.             nlsTitle.LoadString(IDS_LOGONTITLE);
  295.             nlsMessage.LoadString(IDS_BADPASSWORD);
  296.             ::MessageBox(hwndDialog, nlsMessage.QueryPch(), nlsTitle.QueryPch(), MB_ICONSTOP | MB_OK);
  297.         }
  298.         ::SetFocus(hwndPassword);
  299.         ::SendMessage(hwndPassword, EM_SETSEL, (WPARAM)(INT)0, (WPARAM)(INT)-1);
  300.     }
  301.     return FALSE;
  302. }
  303. void DestroyUserList(HWND hwndLB)
  304. {
  305.     DWORD cItems = ::SendMessage(hwndLB, LB_GETCOUNT, 0, 0);
  306.     for (DWORD iItem = 0; iItem < cItems; iItem++) {
  307.         IUser *pUser = (IUser *)::SendMessage(hwndLB, LB_GETITEMDATA, iItem, 0);
  308.         if (pUser != NULL) {
  309.             pUser->Release();
  310.         }
  311.     }
  312. }
  313. void ExitLogonDialog(HWND hwndDialog, DWORD err)
  314. {
  315.     DestroyUserList(GetDlgItem(hwndDialog, IDC_USERNAME));
  316.     LogonData *pld = (LogonData *)::GetWindowLongPtr(hwndDialog, DWL_USER);
  317.     if (pld->hbmTransparent != NULL)
  318.         DeleteObject(pld->hbmTransparent);
  319.     ::EndDialog(hwndDialog, err);
  320. }
  321. extern "C" {
  322. BOOL LogonDlgProc(
  323.     HWND hwndDlg,
  324.     UINT msg,
  325.     WPARAM wParam,
  326.     LPARAM lParam
  327.     )
  328. {
  329. #if 0   /*** no help for now ***/
  330.     // Help text array
  331.     static DWORD aIds[] = {
  332.         IDC_DUMMY1, IDH_NET_LOG_USERNAME,
  333.         IDD_LOG_USERNAME, IDH_NET_LOG_USERNAME,
  334.         IDC_DUMMY2, IDH_NET_LOG_PASSWORD,
  335.         IDD_LOG_PASSWORD, IDH_NET_LOG_PASSWORD,
  336.         IDC_LOGOFRAME, NO_HELP,
  337.         IDC_DUMMY3, NO_HELP,
  338.         0,0
  339.     };
  340. #endif
  341.     switch (msg) {
  342.     case WM_INITDIALOG:
  343.         {
  344.             DWORD err = ::InitLogonDialog(hwndDlg, (LogonData *)lParam);
  345.             if (err != ERROR_SUCCESS) {
  346.                 ::ExitLogonDialog(hwndDlg, err);
  347.             }
  348.         }
  349.         return FALSE;           /* we set the focus */
  350.     case WM_COMMAND:
  351.         switch (LOWORD(wParam)) {
  352.         case IDCANCEL:
  353.             ::ExitLogonDialog(hwndDlg, WN_CANCEL);
  354.             return TRUE;        /* we processed a message */
  355.         case IDOK:
  356.             if (::ValidateLogonDialog(hwndDlg))
  357.                 ::ExitLogonDialog(hwndDlg, WN_SUCCESS);
  358.             return TRUE;        /* we processed a message */
  359.         case IDC_USERNAME:
  360.             if (HIWORD(wParam) == LBN_SELCHANGE) {
  361.                 int iItem = (int)::SendDlgItemMessage(hwndDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  362.                 UserSelected((HWND)lParam, iItem);
  363.             }
  364.         }
  365.         break;
  366. #if 0   /*** no help for now ***/
  367.     case WM_HELP:
  368.         WinHelp( ((LPHELPINFO)lParam)->hItemHandle, szHelpFile,
  369.                 HELP_WM_HELP, (DWORD)(LPVOID)aIds );
  370.         return TRUE;
  371.     case WM_CONTEXTMENU:
  372.         WinHelp( (HWND)wParam, szHelpFile, HELP_CONTEXTMENU,
  373.                 (DWORD)(LPVOID)aIds );
  374.         return TRUE;
  375. #endif
  376.     }
  377.     return FALSE;               /* we didn't process the message */
  378. }
  379. };  /* extern "C" */
  380. DWORD DoLogonDialog(HWND hwndOwner, LPLOGONINFO lpAuthentInfo)
  381. {
  382.     LogonData ld;
  383.     ld.lpAuthentInfo = lpAuthentInfo;
  384.     ld.dwFlags = 0;
  385.     ld.ppOut = NULL;
  386.     ld.hbmTransparent = NULL;
  387.     int nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
  388.                                 hwndOwner, (DLGPROC)LogonDlgProc, (LPARAM)&ld);
  389.     if (nRet == -1)
  390.         return WN_OUT_OF_MEMORY;
  391.     else
  392.         return (DWORD)nRet;
  393. }
  394. HRESULT DoUserDialog(HWND hwndOwner, DWORD dwFlags, IUser **ppOut)
  395. {
  396.     LogonData ld;
  397.     ld.lpAuthentInfo = NULL;
  398.     ld.dwFlags = dwFlags;
  399.     ld.ppOut = ppOut;
  400.     if (ppOut != NULL)
  401.         *ppOut = NULL;
  402.     int nRet = ::DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_LOGON),
  403.                                 hwndOwner, (DLGPROC)LogonDlgProc, (LPARAM)&ld);
  404.     if (nRet == -1)
  405.         return E_OUTOFMEMORY;
  406.     else
  407.         return (nRet == WN_SUCCESS) ? S_OK : E_ABORT;
  408. }
  409. DWORD TryDefaultLogon(LPCSTR pszUsername, LPCSTR pszPassword, LPLOGONINFO lpAuthentInfo)
  410. {
  411.     IUserDatabase *pDB = NULL;
  412.     if (FAILED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  413.         return WN_OUT_OF_MEMORY;
  414.     }
  415.     DWORD err;
  416.     IUser *pUser;
  417.     if (SUCCEEDED(pDB->GetUser(pszUsername, &pUser))) {
  418.         if (SUCCEEDED(pUser->Authenticate(pszPassword)))
  419.             err = WN_SUCCESS;
  420.         else
  421.             err = WN_BAD_PASSWORD;
  422.         pUser->Release();
  423.     }
  424.     else {
  425.         err = WN_BAD_USER;
  426.     }
  427.     pDB->Release();
  428.     if (err == WN_SUCCESS) {
  429.         DWORD cbUsername = lpAuthentInfo->cbUsername;
  430.         DWORD cbPassword = lpAuthentInfo->cbPassword;
  431.         NPSCopyString(pszUsername, lpAuthentInfo->lpUsername, &cbUsername);
  432.         NPSCopyString(pszPassword, lpAuthentInfo->lpPassword, &cbPassword);
  433.     }
  434.     return err;
  435. }
  436. SPIENTRY NPLogon(
  437.     HWND hwndOwner,
  438.     LPLOGONINFO lpAuthentInfo,
  439.     LPLOGONINFO lpPreviousAuthentInfo,
  440.     LPTSTR lpLogonScript,
  441.     DWORD dwBufferSize,
  442.     DWORD dwFlags
  443.     )
  444. {
  445.     /* ignore logon done notification, we only act on logon starting */
  446.     if (dwFlags & LOGON_DONE) {
  447.         return WN_SUCCESS;
  448.     }
  449.     /* we have nothing to do if we're not the primary logon provider */
  450.     if (!(dwFlags & LOGON_PRIMARY)) {
  451.         return WN_SUCCESS;
  452.     }
  453.     /* make sure profiles are enabled, fall back to windows logon if not */
  454.     HKEY hkeyLogon;
  455.     DWORD err;
  456.     DWORD fProfilesEnabled = FALSE;
  457.     DWORD cbData = sizeof(fProfilesEnabled);
  458.     err = ::RegOpenKey(HKEY_LOCAL_MACHINE, ::szLogonKey, &hkeyLogon);
  459.     if (err != ERROR_SUCCESS)
  460.         return WN_NO_NETWORK;
  461.     err = ::RegQueryValueEx(hkeyLogon, ::szUserProfiles, NULL, NULL,
  462.                             (LPBYTE)&fProfilesEnabled, &cbData);
  463.     ::RegCloseKey(hkeyLogon);
  464.     if (err != ERROR_SUCCESS || !fProfilesEnabled)
  465.         return WN_NO_NETWORK;
  466.     /* If we have cached logon credentials, attempt to use them. */
  467.     if (fDoDefaultLogon) {
  468.         DeObfuscateString(szDefaultLogonUsername);
  469.         DeObfuscateString(szDefaultLogonPassword);
  470.         DWORD err = TryDefaultLogon(szDefaultLogonUsername, szDefaultLogonPassword, lpAuthentInfo);
  471.         ::memsetf(szDefaultLogonUsername, '', sizeof(szDefaultLogonUsername));
  472.         ::memsetf(szDefaultLogonPassword, '', sizeof(szDefaultLogonPassword));
  473.         fDoDefaultLogon = FALSE;
  474.         if (err == WN_SUCCESS)
  475.             return WN_SUCCESS;
  476.     }
  477.     return DoLogonDialog(hwndOwner, lpAuthentInfo);
  478. }
  479. SPIENTRY NPLogoff(
  480.     HWND hwndOwner,
  481.     LPLOGONINFO lpAuthentInfo,
  482.     DWORD dwReason
  483.     )
  484. {
  485.     return WN_SUCCESS;
  486. }
  487. SPIENTRY NPGetPolicyPath(
  488.     LPTSTR lpPath,
  489.     LPDWORD lpBufferSize,
  490.     DWORD dwFlags
  491.     )
  492. {
  493.     return WN_NOT_SUPPORTED;
  494. }