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

Windows Kernel

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. //
  4. // registry information
  5. //
  6. const WCHAR c_szWinLogon[]          = L"Software\Microsoft\Windows NT\CurrentVersion\WinLogon";
  7. const WCHAR c_szAutoLogon[]         = L"AutoAdminLogon";
  8. const WCHAR c_szDisableCAD[]        = L"DisableCAD";
  9. const WCHAR c_szDefUserName[]       = L"DefaultUserName";
  10. const WCHAR c_szDefDomain[]         = L"DefaultDomainName";
  11. const WCHAR c_szDefPassword[]       = L"DefaultPassword";
  12. const WCHAR c_szDefaultPwdKey[]     = L"DefaultPassword";
  13. //
  14. // registry helpers
  15. //
  16. BOOL _RegSetSZ(HKEY hk, LPCWSTR pszValueName, LPCWSTR pszValue)
  17. {
  18.     DWORD dwSize = lstrlen(pszValue)*SIZEOF(WCHAR);
  19.     return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_SZ, (BYTE *)pszValue, dwSize);
  20. }
  21. BOOL _RegSetDWORD(HKEY hk, LPCWSTR pszValueName, DWORD dwValue)
  22. {
  23.     DWORD dwSize = SIZEOF(dwValue);
  24.     return ERROR_SUCCESS == RegSetValueEx(hk, pszValueName, 0x0, REG_DWORD, (BYTE *)&dwValue, dwSize);
  25. }
  26. BOOL _RegDelValue(HKEY hk, LPCWSTR pszValueName)
  27. {
  28.     return ERROR_SUCCESS == RegDeleteValue(hk, pszValueName);
  29. }
  30. INT_PTR CALLBACK _CredDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  31. {
  32.     LPCREDINFO pci = (LPCREDINFO)GetWindowLongPtr(hwnd, DWLP_USER);
  33.     switch ( uMsg ) 
  34.     {
  35.         case WM_INITDIALOG:
  36.         {
  37.             pci = (LPCREDINFO)lParam;
  38.             SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  39.             SetDlgItemText(hwnd, IDC_USER, pci->pszUser);
  40.             Edit_LimitText(GetDlgItem(hwnd, IDC_USER), pci->cchUser - 1);
  41.             SetDlgItemText(hwnd, IDC_DOMAIN, pci->pszDomain);
  42.             Edit_LimitText(GetDlgItem(hwnd, IDC_DOMAIN), pci->cchDomain - 1);
  43.             SetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword);
  44.             Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), pci->cchPassword - 1);
  45.             return TRUE;
  46.         }
  47.         case WM_COMMAND:
  48.         {
  49.             switch ( LOWORD(wParam) )
  50.             {
  51.                 case IDOK:
  52.                     {
  53.                         FetchText(hwnd, IDC_DOMAIN, pci->pszDomain, pci->cchDomain);
  54.                         FetchText(hwnd, IDC_USER, pci->pszUser, pci->cchUser);
  55.                         if (StrChr(pci->pszUser, TEXT('@')))
  56.                         {
  57.                             *(pci->pszDomain) = 0;
  58.                         }
  59.                         GetDlgItemText(hwnd, IDC_PASSWORD, pci->pszPassword, pci->cchPassword);
  60.                         return EndDialog(hwnd, IDOK);
  61.                     }
  62.                 case IDCANCEL:
  63.                     return EndDialog(hwnd, IDCANCEL);
  64.                 case IDC_USER:
  65.                 {
  66.                     if ( HIWORD(wParam) == EN_CHANGE )
  67.                     {
  68.                         EnableWindow(GetWindow(hwnd, IDOK), FetchTextLength(hwnd, IDC_USER) > 0);
  69.                         EnableDomainForUPN(GetDlgItem(hwnd, IDC_USER), GetDlgItem(hwnd, IDC_DOMAIN));
  70.                     }
  71.                     break;
  72.                 }
  73.             }
  74.             return TRUE;
  75.         }
  76.     }
  77.     return FALSE;
  78. }
  79. //
  80. // attempt to join a domain/workgroup using the specified names and OU.
  81. //
  82. HRESULT _AttemptJoin(HWND hwnd, DWORD dwFlags, LPCWSTR pszDomain, LPCWSTR pszUser, LPCWSTR pszUserDomain, LPCWSTR pszPassword)
  83. {
  84. #ifndef DONT_JOIN
  85.     HRESULT hres = E_FAIL;
  86.     NET_API_STATUS nas;
  87.     TCHAR szDomainUser[MAX_DOMAINUSER + 1];
  88.     TraceEnter(TRACE_PSW, "_AttemptJoin");
  89.     Trace(TEXT("dwFlags %x"), dwFlags);
  90.     Trace(TEXT("pszDomain: %s, pszUser: %s, pszUserDomain: %s"), pszDomain, 
  91.                         pszUser ? pszUser:TEXT("<NULL>"), 
  92.                         pszUserDomain ? pszUserDomain:TEXT("<NULL>"));
  93.     if ( pszUser )
  94.     {
  95.         MakeDomainUserString(pszUserDomain, pszUser, szDomainUser, ARRAYSIZE(szDomainUser));
  96.     }
  97.     Trace(TEXT("NetJoinDomain (1st); pszDomain: %s, dwFlags %x"), pszDomain, dwFlags);
  98.     nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, pszPassword, dwFlags);
  99.     
  100.     if ( (nas == ERROR_ACCESS_DENIED) )
  101.     {
  102.         TraceMsg("NetJoinDomain returned ERROR_ACCESS_DENIED");
  103.         // perhaps an account exists, but we can't delete it so try and remove
  104.         // the account create flag
  105.         if ( dwFlags & NETSETUP_ACCT_CREATE )
  106.         {    
  107.             TraceMsg("Trying NetJoinDomain without NETSETUP_ACCT_CREATE flag");
  108.             dwFlags &= ~NETSETUP_ACCT_CREATE;
  109.             nas = NetJoinDomain(NULL, pszDomain, NULL, szDomainUser, *pszPassword ? pszPassword : NULL, dwFlags);
  110.         }
  111.     }
  112.     if ( (nas != NERR_Success) && (nas != NERR_SetupAlreadyJoined) )
  113.     {
  114.         Trace(TEXT("Failed in NetJoinDomain %x (%d)"), nas, nas);
  115. // BUGBUG: tell the user why
  116.         ExitGracefully(hres, E_FAIL, "Failed to join the new domain/workgroup");
  117.     }
  118.     hres = S_OK;            // success
  119. exit_gracefully:
  120.     if (FAILED(hres))
  121.     {
  122.         TCHAR szMessage[512];
  123.         DWORD dwFormatResult = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) nas, 0, szMessage, ARRAYSIZE(szMessage), NULL);
  124.         if (0 == dwFormatResult)
  125.         {
  126.             LoadString(g_hInstance, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
  127.         }
  128.         ::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_NAW_JOIN_GENERICERROR, MB_OK|MB_ICONERROR, szMessage);
  129.     }
  130.     TraceLeaveResult(hres);
  131. #else
  132.     TraceEnter(TRACE_PSW, "_AttemptJoin");
  133.     TraceLeaveResult(S_OK);
  134. #endif
  135. }
  136. //
  137. // Handle moving from to a workgroup or domain.  To do this we are passed
  138. // a structure containing all the information we need.
  139. //
  140. HRESULT JoinDomain(HWND hwnd, BOOL fDomain, LPCWSTR pszDomain, CREDINFO* pci)
  141. {
  142.     HRESULT hres = E_FAIL;
  143.     DWORD dwFlags = 0x0;
  144.     LPWSTR pszCurrentDomain = NULL;
  145.     NET_API_STATUS nas;
  146.     BOOL fPassedCredentials = (pci && pci->pszUser && pci->pszUser[0] && pci->pszPassword);
  147.     DECLAREWAITCURSOR;
  148.     SetWaitCursor();
  149.     if (fDomain && !pci)
  150.         ExitGracefully(hres, E_INVALIDARG, "Failed to pass a PCI when fDomain is TRUE");
  151.     TraceEnter(TRACE_PSW, "JoinDomain");
  152.     Trace(TEXT("fDomain %d, pszDomain: %s, pszUser: %s, pszUserDomain: %s"),
  153.                     fDomain, pszDomain, 
  154.                     (pci && pci->pszUser) ? pci->pszUser:TEXT("<NULL>"),
  155.                     (pci && pci->pszDomain) ? pci->pszDomain:TEXT("<NULL>"));
  156.     //
  157.     // lets validate the domain name before we go and use it, therefore avoiding
  158.     // orphaning the computer too badly
  159.     //
  160.     nas = NetValidateName(NULL, pszDomain, NULL, NULL, fDomain ? NetSetupDomain:NetSetupWorkgroup);
  161.     if ( NERR_Success != nas )
  162.     {
  163.         Trace(TEXT("NetValidateName returned %x (%d)"), nas, nas);
  164.         ShellMessageBox(GLOBAL_HINSTANCE, hwnd,
  165.                         fDomain ? MAKEINTRESOURCE(IDS_ERR_BADDOMAIN) : MAKEINTRESOURCE(IDS_ERR_BADWORKGROUP), 
  166.                         MAKEINTRESOURCE(IDS_NETWIZCAPTION),
  167.                         MB_OK|MB_ICONWARNING,
  168.                         pszDomain);
  169.         ExitGracefully(hres, E_FAIL, "Bad domain specified");
  170.     }
  171.     // 
  172.     // now attempt to join the domain, prompt for credentails if the ones
  173.     // specified are not good enough
  174.     //
  175.     TraceMsg("Doing the domain change");
  176.     if ( fDomain )
  177.     {
  178.         TraceMsg("Attempting domain join so setting: NETSETUP_JOIN_DOMAIN|NETSETUP_ACCT_CREATE|NETSETUP_DOMAIN_JOIN_IF_JOINED");
  179.         dwFlags |= NETSETUP_JOIN_DOMAIN|NETSETUP_ACCT_CREATE|NETSETUP_DOMAIN_JOIN_IF_JOINED;
  180.     }
  181.     else
  182.     {
  183.         TraceMsg("Attempting to join a WORKGROUP, so leaving where we are now");
  184.         nas = NetUnjoinDomain(NULL, NULL, NULL, NETSETUP_ACCT_DELETE);
  185.         if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
  186.         {
  187.             Trace(TEXT("NetUnjoinDomain returned %x (%d) - trying again with no delete"), nas, nas);
  188.             nas = NetUnjoinDomain(NULL, NULL, NULL, 0x0);
  189.         }
  190.         if ( (nas != NERR_Success) && (nas != NERR_SetupNotJoined) )
  191.         {
  192.             Trace(TEXT("Failed in NetUnjoinDomain %x (%d)"), nas, nas);
  193.             ExitGracefully(hres, E_UNEXPECTED, "Computer object orphaned");
  194.         }
  195.         g_fRebootOnExit = TRUE;               // we changed the domain
  196.     }
  197.     if ( !fDomain || fPassedCredentials)
  198.     {
  199.         TraceMsg("Not a domain join, or we have user information so using to call _AttemptJoin");
  200.         if (fPassedCredentials)
  201.         {
  202.             hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
  203.         }
  204.         else
  205.         {
  206.             hres = _AttemptJoin(hwnd, dwFlags, pszDomain, NULL, NULL, NULL);
  207.         }
  208.     }
  209.     if ( fDomain && ((FAILED(hres) || (!fPassedCredentials))) )
  210.     {
  211.         TraceMsg("Either a domain join (and failed first time, or we didn't have credentials");
  212.         do
  213.         {
  214.             TraceMsg("Prompting to credentials");
  215.             if ( IDCANCEL == DialogBoxParam(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDD_PSW_JOINCREDENTIALS), 
  216.                                                 hwnd, _CredDlgProc, (LPARAM)pci) )
  217.             {
  218.                 ExitGracefully(hres, E_FAIL, "User pressed 'Cancel' in user credentails");
  219.             }
  220.             // The dialog box changed the cursor from a wait cursor to an arrow cursor, so the cursor
  221.             // needs to be changed back.. This call could be moved to _AttemptJoin (along with a call to
  222.             // reset the cursor).  This call is made synchronously from the message loop for this hwnd
  223.             SetCursor(LoadCursor(NULL, IDC_WAIT));
  224.             TraceMsg("Trying to join again");
  225.             hres = _AttemptJoin(hwnd, dwFlags, pszDomain, pci->pszUser, pci->pszDomain, pci->pszPassword);
  226.         }
  227.         while ( FAILED(hres) );
  228.     }
  229. exit_gracefully:
  230.     ResetWaitCursor();
  231.     if ( SUCCEEDED(hres) )
  232.     {
  233.        ClearAutoLogon();
  234.         g_fRebootOnExit = TRUE;               // we changed the domain
  235.     }
  236.     NetApiBufferFree(pszCurrentDomain);
  237.     TraceLeaveResult(hres);                                                                                                                                                                 
  238. }
  239. //
  240. // set and clear the auto admin logon state.
  241. //
  242. // we set the default user and default domain to the specified strings, we then blow away
  243. // the clear text password stored in the registry to replace it with a password stored
  244. // in the LSA secret space.
  245. //
  246. NTSTATUS _SetDefaultPassword(LPCWSTR PasswordBuffer)
  247. {
  248.     NTSTATUS Status = STATUS_SUCCESS;
  249.     OBJECT_ATTRIBUTES ObjectAttributes;
  250.     LSA_HANDLE LsaHandle = NULL;
  251.     UNICODE_STRING SecretName;
  252.     UNICODE_STRING SecretValue;
  253.     InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, (HANDLE)NULL, NULL);
  254.     Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_CREATE_SECRET, &LsaHandle);
  255.     if (!NT_SUCCESS(Status))
  256.         return Status;
  257.     RtlInitUnicodeString(&SecretName, c_szDefaultPwdKey);
  258.     RtlInitUnicodeString(&SecretValue, PasswordBuffer);
  259.     Status = LsaStorePrivateData(LsaHandle, &SecretName, &SecretValue);
  260.     LsaClose(LsaHandle);
  261.     return Status;
  262. }
  263. //
  264. // Set and clear auto logon for a particular
  265. //
  266. VOID SetAutoLogon(LPCWSTR pszUserName, LPCWSTR pszPassword)
  267. {
  268. #ifndef DONT_JOIN
  269.     WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  270.     DWORD dwComputerName = ARRAYSIZE(szComputerName);
  271.     HKEY hk;
  272.     TraceEnter(TRACE_PSW, "SetAutoLogon");
  273.     Trace(TEXT("pszUserName: %s"), pszUserName);
  274.     GetComputerName(szComputerName, &dwComputerName);
  275.     SetDefAccount(pszUserName, szComputerName);         // also clears auto logon
  276.     if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  277.     {
  278.         _RegSetSZ(hk, c_szAutoLogon, L"1");             // auto admin logon
  279.         _RegDelValue(hk, c_szDefPassword);              // use the LSA secret for the password
  280.         RegCloseKey (hk);
  281.     }
  282.     _SetDefaultPassword(pszPassword);    
  283.     TraceLeave();
  284. #endif
  285. }
  286. //
  287. // clear the auto admin logon
  288. //
  289. STDAPI ClearAutoLogon(VOID)
  290. {
  291. #ifndef DONT_JOIN
  292.     TraceEnter(TRACE_PSW, "ClearAutoLogon");
  293.     HKEY hk;
  294.     if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  295.     {
  296.         _RegSetSZ(hk, c_szAutoLogon, L"0");         // no auto admin logon
  297.         _RegDelValue(hk, c_szDefPassword);  
  298.         RegCloseKey(hk);
  299.     }
  300.     _SetDefaultPassword(L"");            // clear the LSA secret
  301.     TraceLeave();
  302. #endif
  303.     return(S_OK);
  304. }
  305. //
  306. // set the default account
  307. //
  308. VOID SetDefAccount(LPCWSTR pszUser, LPCWSTR pszDomain)
  309. {
  310. #ifndef DONT_JOIN
  311.     HKEY hk;
  312.     TraceEnter(TRACE_PSW, "SetDefAccount");
  313.    ClearAutoLogon();
  314.     if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinLogon, 0x0, KEY_WRITE, &hk) )
  315.     {
  316.         _RegSetSZ(hk, c_szDefUserName, pszUser);             
  317.         _RegSetSZ(hk, c_szDefDomain, pszDomain);
  318.        RegCloseKey(hk);
  319.     }
  320.     TraceLeave();
  321. #endif
  322. }