Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

502 lines
15 KiB

  1. // UserInfo.cpp: implementation of the CUserInfo class.
  2. // Adapted from the CUserInfo class in the SBS Add User wizard
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "stdafx.h"
  6. #include <sbs6base.h>
  7. #include "UserInfo.h"
  8. #include <atlbase.h>
  9. #include <comdef.h>
  10. #include <dsgetdc.h>
  11. #include <iads.h> // Must come before adshlp.h
  12. #include <adshlp.h>
  13. #include <lm.h>
  14. #include <emolib.h>
  15. #include <AUsrUtil.h>
  16. #ifndef ASSERT
  17. #define ASSERT assert
  18. #endif
  19. #ifndef WSTRING
  20. typedef std::wstring WSTRING; // Move to sbs6base.h
  21. #endif
  22. #ifndef CHECK_HR
  23. #define CHECK_HR( x ) CHECK_HR_RET( x, _hr );
  24. #define CHECK_HR_RET( x, y ) \
  25. { \
  26. HRESULT _hr = x; \
  27. if( FAILED(_hr) ) \
  28. { \
  29. ASSERT( !_T("CHECK_HR_RET() failed. calling TRACE() with HRESULT and statement") ); \
  30. /*::AfxTrace( _T("CHECK_HR_RET() failed, hr == [%d], statement = [%s], returning [%s]"), _hr, #x, #y );*/ \
  31. return y; \
  32. } \
  33. }
  34. #endif // CHECK_HR
  35. // Defines for account flags.
  36. #define PASSWD_NOCHANGE 0x01
  37. #define PASSWD_CANCHANGE 0x02
  38. #define PASSWD_MUSTCHANGE 0x04
  39. #define ACCOUNT_DISABLED 0x10
  40. // ****************************************************************************
  41. // CUserInfo
  42. // ****************************************************************************
  43. // ----------------------------------------------------------------------------
  44. // CUserInfo()
  45. //
  46. // Constructor.
  47. // ----------------------------------------------------------------------------
  48. CUserInfo::CUserInfo()
  49. {
  50. m_dwAccountOptions = 0;
  51. m_bCreateMB = TRUE;
  52. // Store the SBS Server Name
  53. TCHAR szServer[MAX_PATH+1] = {0};
  54. DWORD dwLen = MAX_PATH;
  55. GetComputerName(szServer, &dwLen);
  56. m_csSBSServer = szServer;
  57. // Get domain controller name
  58. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  59. HRESULT hr = DsGetDcName (NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED, &DomainControllerInfo);
  60. ASSERT(hr == S_OK && "DsGetDcName failed");
  61. // cache the domain
  62. if ( DomainControllerInfo )
  63. {
  64. m_csDomainName = DomainControllerInfo->DomainName;
  65. // free memory
  66. NetApiBufferFree (DomainControllerInfo);
  67. }
  68. // convert from '.' separated names to Dc=xxx,DC=yyy,... format
  69. WSTRING tmpDomain = m_csDomainName;
  70. while ( !tmpDomain.empty() )
  71. {
  72. int nPos = tmpDomain.find(_T("."));
  73. if ( nPos == WSTRING::npos )
  74. {
  75. nPos = tmpDomain.length();
  76. }
  77. if ( !m_csFQDomainName.empty() )
  78. {
  79. m_csFQDomainName += _T(",");
  80. }
  81. m_csFQDomainName += _T("DC=");
  82. m_csFQDomainName += tmpDomain.substr( 0, nPos );
  83. tmpDomain.erase( 0, nPos + 1 );
  84. }
  85. }
  86. CUserInfo::~CUserInfo()
  87. {
  88. for ( int i = 0 ; i < m_csPasswd.length() ; i++ )
  89. m_csPasswd[i] = '\0' ;
  90. if ( 0 < m_csPasswd.length()) m_csPasswd[0] = NULL ;
  91. // Make sure that the last operation on the string isn't the origonal assignment.
  92. // The compiler will optimize the last statement out
  93. // if it is an assignment that doesn't get used.
  94. }
  95. // ----------------------------------------------------------------------------
  96. // CreateAccount()
  97. //
  98. // Makes a new user account in the Active Directory.
  99. // ----------------------------------------------------------------------------
  100. HRESULT CUserInfo::CreateAccount()
  101. {
  102. HRESULT hr = S_OK;
  103. BOOL bRO = TRUE;
  104. _bstr_t _bstr;
  105. _bstr_t _bstrClass;
  106. _bstr_t _bstrProperty;
  107. _variant_t _vTmpVal;
  108. CComPtr<IADsContainer> spADsContainer = NULL;
  109. // Bind to the container.
  110. WSTRING csLdapUserOU;
  111. if ( _tcsstr( m_csUserOU.c_str(), L"LDAP://") )
  112. csLdapUserOU = m_csUserOU.c_str();
  113. else
  114. {
  115. if ( m_csUserOU.empty() )
  116. {
  117. csLdapUserOU = L"LDAP://CN=Users," + m_csFQDomainName;
  118. m_csUserOU = csLdapUserOU;
  119. }
  120. else
  121. csLdapUserOU = L"LDAP://" + m_csUserOU;
  122. }
  123. hr = ::ADsGetObject( csLdapUserOU.c_str(), IID_IADsContainer, (VOID**) &spADsContainer );
  124. if ( FAILED(hr) )
  125. return(hr);
  126. // Create the user account.
  127. CComPtr<IDispatch> spDisp = NULL;
  128. _bstr = m_csUserCN.c_str();
  129. _bstrClass = L"user";
  130. hr = spADsContainer->Create( _bstrClass, _bstr, &spDisp );
  131. if ( FAILED(hr) )
  132. {
  133. ASSERT(FALSE);
  134. return(hr);
  135. }
  136. // m_pCmt->m_csADName = L"LDAP://";
  137. // m_pCmt->m_csADName += m_csUserCN;
  138. // m_pCmt->m_csADName += L",";
  139. // m_pCmt->m_csADName += (LPCTSTR)csLdapUserOU+7;
  140. // Use this new account and set it's properties (e.g. first name, home folder, etc.).
  141. CComQIPtr<IADsUser, &IID_IADsUser> spADsUserObj(spDisp);
  142. if ( !spADsUserObj )
  143. {
  144. ASSERT(FALSE);
  145. return(E_FAIL);
  146. }
  147. TCHAR szTmp[MAX_PATH*4] = {0};
  148. LdapToDCName( csLdapUserOU.c_str(), szTmp, (MAX_PATH*4));
  149. WSTRING csUserPrincName = m_csUserName;
  150. csUserPrincName += L"@";
  151. csUserPrincName += szTmp;
  152. EmailAddr = csUserPrincName;
  153. // Username:
  154. _vTmpVal.Clear();
  155. _vTmpVal = ( csUserPrincName.c_str() );
  156. _bstrProperty = L"userPrincipalName";
  157. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  158. {
  159. ASSERT(FALSE);
  160. return(E_FAIL);
  161. }
  162. // Pre-Win2000 username:
  163. _vTmpVal.Clear();
  164. _vTmpVal = ( _tcslen( m_csUserNamePre2k.c_str() ) ? m_csUserNamePre2k.c_str() : m_csUserName.c_str() );
  165. _bstrProperty = L"sAMAccountName";
  166. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  167. {
  168. ASSERT(FALSE);
  169. return(E_FAIL);
  170. }
  171. // Use UserName instead
  172. _bstr = m_csUserName.c_str();
  173. if ( FAILED( spADsUserObj->put_FullName( _bstr )))
  174. {
  175. ASSERT(FALSE);
  176. return(E_FAIL);
  177. }
  178. // Display Name
  179. _vTmpVal.Clear();
  180. _vTmpVal = m_csUserName.c_str();
  181. _bstrProperty = L"displayName";
  182. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  183. {
  184. ASSERT(FALSE);
  185. return(E_FAIL);
  186. }
  187. // Commit this information to the AD.
  188. CHECK_HR( spADsUserObj->SetInfo() );
  189. // Password expired?
  190. _vTmpVal.Clear();
  191. V_VT( &_vTmpVal ) = VT_I4;
  192. V_I4( &_vTmpVal ) = (m_dwAccountOptions & PASSWD_MUSTCHANGE) ? 0 : -1;
  193. _bstrProperty = L"pwdLastSet";
  194. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  195. {
  196. ASSERT(FALSE);
  197. }
  198. // Account disabled?
  199. _vTmpVal.Clear();
  200. _bstrProperty = L"userAccountControl";
  201. if ( FAILED(spADsUserObj->Get( _bstrProperty, &_vTmpVal )) )
  202. {
  203. ASSERT(FALSE);
  204. }
  205. else
  206. {
  207. _vTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
  208. if ( m_dwAccountOptions & ACCOUNT_DISABLED ) // Do we want to disable the account?
  209. _vTmpVal.lVal |= UF_ACCOUNTDISABLE;
  210. else
  211. _vTmpVal.lVal &= ~UF_ACCOUNTDISABLE; // ..not disable the account.
  212. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  213. {
  214. ASSERT(FALSE);
  215. }
  216. }
  217. // Set the password.
  218. hr = SetPasswd();
  219. if ( FAILED( hr ))
  220. {
  221. // m_pCmt->SetErrorResults(ERROR_PASSWORD);
  222. _vTmpVal.Clear();
  223. _bstrProperty = L"userAccountControl";
  224. if ( FAILED(spADsUserObj->Get( _bstrProperty, &_vTmpVal )) )
  225. {
  226. ASSERT(FALSE);
  227. }
  228. else
  229. {
  230. _vTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
  231. _vTmpVal.lVal |= UF_ACCOUNTDISABLE; // Disable the account.
  232. if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
  233. {
  234. ASSERT(FALSE);
  235. }
  236. }
  237. // Commit this information to the AD.
  238. if ( FAILED( spADsUserObj->SetInfo() ))
  239. {
  240. ASSERT(FALSE);
  241. }
  242. return hr;
  243. }
  244. // Commit this information to the AD.
  245. hr = spADsUserObj->SetInfo();
  246. if ( FAILED( hr ))
  247. {
  248. ASSERT(FALSE);
  249. }
  250. return hr;
  251. }
  252. // ----------------------------------------------------------------------------
  253. // CreateMailbox()
  254. //
  255. // Makes a new exchange mailbox for the user.
  256. // ----------------------------------------------------------------------------
  257. HRESULT CUserInfo::CreateMailbox()
  258. {
  259. HRESULT hr = S_OK;
  260. CComVariant _vTmpVal;
  261. CComPtr<IADsContainer> spADsContainer = NULL;
  262. _bstr_t _bstr;
  263. _bstr_t _bstrClass;
  264. if ( 0 == m_csEXHomeMDB.length() )
  265. {
  266. hr = GetMDBPath( m_csEXHomeMDB );
  267. if FAILED( hr )
  268. return hr;
  269. }
  270. // Do we even need to run?
  271. if ( 0 == m_csEXHomeMDB.length() || 0 == m_csEXAlias.length() )
  272. return(hr);
  273. // Bind to the container.
  274. WSTRING csLdapUserOU = L"LDAP://";
  275. if ( _tcsstr( m_csUserOU.c_str(), L"LDAP://") )
  276. csLdapUserOU = m_csUserOU.c_str();
  277. else
  278. {
  279. if ( m_csUserOU.empty() )
  280. {
  281. csLdapUserOU = L"LDAP://CN=Users," + m_csFQDomainName;
  282. m_csUserOU = csLdapUserOU;
  283. }
  284. else
  285. csLdapUserOU = L"LDAP://" + m_csUserOU;
  286. }
  287. hr = ::ADsGetObject( csLdapUserOU.c_str(), IID_IADsContainer, (VOID**) &spADsContainer );
  288. if ( FAILED(hr) || !spADsContainer )
  289. {
  290. ASSERT(FALSE);
  291. return(hr);
  292. }
  293. // Open the user account.
  294. CComPtr<IDispatch> spDisp = NULL;
  295. _bstr = m_csUserCN.c_str();
  296. _bstrClass = L"user";
  297. hr = spADsContainer->GetObject( _bstrClass, _bstr, &spDisp );
  298. // if ( !spDisp ) // If the user doesn't exist, create it.
  299. // hr = spADsContainer->Create( L"user", (LPWSTR)(LPCWSTR)m_csUserCN, &spDisp );
  300. // return(hr); // Let's just return.. maybe we'll want to change to create later?
  301. if ( !spDisp ) // Was there a problem getting the account (either existing or new)?
  302. {
  303. ASSERT(FALSE);
  304. return(hr);
  305. }
  306. // Get a handle on the user.
  307. CComPtr<IADsUser> spADsUserObj;
  308. hr = spDisp->QueryInterface ( __uuidof(IADsUser), (void**)&spADsUserObj );
  309. if ( FAILED(hr) || !spADsUserObj ) // Was there a problem getting the user object?
  310. {
  311. ASSERT(FALSE);
  312. return(hr);
  313. }
  314. // Get the interface needed to deal with the mailbox.
  315. CComPtr<IMailboxStore> spMailboxStore;
  316. hr = spADsUserObj->QueryInterface ( __uuidof(IMailboxStore), (void**)&spMailboxStore );
  317. if ( FAILED(hr) || !spMailboxStore ) // Was there a problem getting the mailbox store interface?
  318. {
  319. ASSERT(FALSE);
  320. return(hr);
  321. }
  322. // if ( SUCCEEDED( hr ) )
  323. // { // Need to set the mailNickname first otherwise the alias will always be manufactured from the name.
  324. // m_csEXAlias = CreateEmailName( m_csEXAlias );
  325. // m_csEXAlias.TrimLeft();
  326. // m_csEXAlias.TrimRight();
  327. // if ( 0 == m_csEXAlias.length( ) )
  328. // {
  329. // m_csEXAlias.LoadString( IDS_NOLOC_USEREMAILALIAS );
  330. // }
  331. //
  332. // CComBSTR bszTmp = (LPCTSTR) m_csEXAlias;
  333. // VARIANT v;
  334. //
  335. // VariantInit( &v );
  336. // V_VT( &v ) = VT_BSTR;
  337. // V_BSTR( &v ) = bszTmp;
  338. // hr = spADsUserObj->Put( L"mailNickname", v );
  339. // }
  340. if ( SUCCEEDED( hr ) )
  341. { // Create the mailbox.
  342. WSTRING csLdapHomeMDB = L"LDAP://";
  343. csLdapHomeMDB += m_csEXHomeMDB;
  344. _bstr = csLdapHomeMDB.c_str();
  345. hr = spMailboxStore->CreateMailbox( _bstr );
  346. if ( hr == S_OK ) // If it's a new mailbox, set the info.
  347. {
  348. hr = spADsUserObj->SetInfo();
  349. }
  350. if ( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS ) // If it already exists, just move on.
  351. {
  352. hr = S_OK;
  353. }
  354. }
  355. if ( FAILED(hr) ) // Was there a problem?
  356. {
  357. ASSERT(FALSE);
  358. return(hr);
  359. }
  360. return(hr);
  361. }
  362. // ----------------------------------------------------------------------------
  363. // SetPasswd()
  364. // ----------------------------------------------------------------------------
  365. HRESULT CUserInfo::SetPasswd()
  366. {
  367. HRESULT hr = S_OK;
  368. WSTRING csUser = _T("LDAP://");
  369. if ( _tcsstr( m_csUserOU.c_str(), _T("LDAP://")) )
  370. {
  371. csUser += m_csUserCN;
  372. csUser += _T(",");
  373. csUser += m_csUserOU.c_str() + 7;
  374. }
  375. else
  376. {
  377. csUser += m_csUserCN;
  378. csUser += _T(",");
  379. csUser += m_csUserOU.c_str();
  380. }
  381. // Now csUser is something like "LDAP://CN=JohnDoe,DC=Blah"
  382. CComPtr<IADsUser> spDS = NULL;
  383. hr = ::ADsGetObject( csUser.c_str(), IID_IADsUser, (void**)&spDS );
  384. CHECK_HR(hr);
  385. // Set the password.
  386. if ( m_csPasswd.length() ) // Only if there IS a passwd!
  387. {
  388. CComBSTR bszPasswd = m_csPasswd.c_str();
  389. hr = spDS->SetPassword(bszPasswd);
  390. CHECK_HR(hr);
  391. }
  392. // Allow change?
  393. if ( m_dwAccountOptions & PASSWD_NOCHANGE )
  394. {
  395. CComVariant vaTmpVal;
  396. CComBSTR bstrProp = _T("UserFlags");
  397. vaTmpVal.Clear();
  398. hr = spDS->Get( bstrProp, &vaTmpVal );
  399. CHECK_HR(hr);
  400. vaTmpVal.lVal |= UF_PASSWD_CANT_CHANGE;
  401. hr = spDS->Put( bstrProp, vaTmpVal );
  402. CHECK_HR(hr);
  403. }
  404. // SetInfo only if we actually changed anything.
  405. if ( ( m_csPasswd.length()) || // Did we mess with the passwd?
  406. ( m_dwAccountOptions & PASSWD_NOCHANGE ) ) // Did we make it unable to change?
  407. {
  408. hr = spDS->SetInfo(); // If either, then set the new info.
  409. }
  410. return hr;
  411. }
  412. /////////////////////////////////////////////////////////////////////////////////////
  413. // SetUserName
  414. // Set the user name and dependant member variables (m_csUserCN, m_csEXAlias)
  415. /////////////////////////////////////////////////////////////////////////////////////
  416. HRESULT CUserInfo::SetUserName( LPCTSTR szUserName )
  417. {
  418. m_csUserName = szUserName;
  419. m_csUserCN = L"CN=" + m_csUserName;
  420. m_csEXAlias = szUserName;
  421. return S_OK;
  422. }
  423. /////////////////////////////////////////////////////////////////////////////////////
  424. // SetPassword
  425. // Set the Password
  426. /////////////////////////////////////////////////////////////////////////////////////
  427. HRESULT CUserInfo::SetPassword( LPCTSTR szPassword )
  428. {
  429. m_csPasswd = szPassword;
  430. return S_OK;
  431. }