Source code of Windows XP (NT5)
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.

491 lines
15 KiB

  1. // CSvcInf.cpp : Implementation of CCSvcAcctInfo
  2. #include "stdafx.h"
  3. #include "McsPISag.h"
  4. //#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids
  5. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  6. #import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty")
  7. #import "DBMgr.tlb" no_namespace, named_guids
  8. #include "CSvcInf.h"
  9. #include "ResStr.h"
  10. #include "ErrDct.hpp"
  11. #include <ntdsapi.h>
  12. #include <lm.h>
  13. #include <dsgetdc.h>
  14. // these are needed for ISecPlugIn
  15. #include "cipher.hpp"
  16. #include "SecPI.h"
  17. #define EXCHANGE_SERVICE_NAME L"MSExchangeSA"
  18. #define SvcAcctStatus_DoNotUpdate 1
  19. #define SvcAcctStatus_NeverAllowUpdate 8
  20. TErrorDct err;
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CCSvcAcctInfo
  23. typedef UINT (CALLBACK* DSBINDFUNC)(TCHAR*, TCHAR*, HANDLE*);
  24. typedef UINT (CALLBACK* DSUNBINDFUNC)(HANDLE*);
  25. // Win2k function
  26. typedef HRESULT (CALLBACK * DSGETDCNAME)(LPWSTR, LPWSTR, GUID*, LPWSTR, DWORD, PDOMAIN_CONTROLLER_INFO*);
  27. typedef NTDSAPI
  28. DWORD
  29. WINAPI
  30. DSCRACKNAMES(
  31. HANDLE hDS, // in
  32. DS_NAME_FLAGS flags, // in
  33. DS_NAME_FORMAT formatOffered, // in
  34. DS_NAME_FORMAT formatDesired, // in
  35. DWORD cNames, // in
  36. const LPCWSTR *rpNames, // in
  37. PDS_NAME_RESULTW *ppResult); // out
  38. typedef NTDSAPI
  39. void
  40. WINAPI
  41. DSFREENAMERESULT(
  42. DS_NAME_RESULTW *pResult
  43. );
  44. // This method is called by the dispatcher to verify that this is a valid plug-in
  45. // Only valid plug-ins will be sent out with the agents
  46. // The purpose of this check is to make it more difficult for unauthorized parties
  47. // to use our plug-in interface, since it is currently undocumented.
  48. STDMETHODIMP CCSvcAcctInfo::Verify(/*[in,out]*/ULONG * pData,/*[in]*/ULONG size)
  49. {
  50. McsChallenge * pMcsChallenge;
  51. long lTemp1;
  52. long lTemp2;
  53. if( size == sizeof(McsChallenge) )
  54. {
  55. pMcsChallenge = (McsChallenge*)(pData);
  56. SimpleCipher((LPBYTE)pMcsChallenge,size);
  57. pMcsChallenge->MCS[0] = 'M';
  58. pMcsChallenge->MCS[1] = 'C';
  59. pMcsChallenge->MCS[2] = 'S';
  60. pMcsChallenge->MCS[3] = 0;
  61. lTemp1 = pMcsChallenge->lRand1 + pMcsChallenge->lRand2;
  62. lTemp2 = pMcsChallenge->lRand2 - pMcsChallenge->lRand1;
  63. pMcsChallenge->lRand1 = lTemp1;
  64. pMcsChallenge->lRand2 = lTemp2;
  65. pMcsChallenge->lTime += 100;
  66. SimpleCipher((LPBYTE)pMcsChallenge,size);
  67. }
  68. else
  69. return E_FAIL;
  70. return S_OK;
  71. }
  72. STDMETHODIMP CCSvcAcctInfo::GetRegisterableFiles(/* [out] */SAFEARRAY ** pArray)
  73. {
  74. SAFEARRAYBOUND bound[1] = { 1, 0 };
  75. LONG ndx[1] = { 0 };
  76. (*pArray) = SafeArrayCreate(VT_BSTR,1,bound);
  77. SafeArrayPutElement(*pArray,ndx,SysAllocString(L"McsPISag.DLL"));
  78. return S_OK;
  79. }
  80. STDMETHODIMP CCSvcAcctInfo::GetRequiredFiles(/* [out] */SAFEARRAY ** pArray)
  81. {
  82. SAFEARRAYBOUND bound[1] = { 1, 0 };
  83. LONG ndx[1] = { 0 };
  84. (*pArray) = SafeArrayCreate(VT_BSTR,1,bound);
  85. SafeArrayPutElement(*pArray,ndx,SysAllocString(L"McsPISag.DLL"));
  86. return S_OK;
  87. }
  88. STDMETHODIMP CCSvcAcctInfo::GetDescription(/* [out] */ BSTR * description)
  89. {
  90. (*description) = SysAllocString(L"");
  91. return S_OK;
  92. }
  93. STDMETHODIMP CCSvcAcctInfo::PreMigrationTask(/* [in] */IUnknown * pVarSet)
  94. {
  95. return S_OK;
  96. }
  97. STDMETHODIMP CCSvcAcctInfo::PostMigrationTask(/* [in] */IUnknown * pVarSet)
  98. {
  99. // DWORD rc = 0;
  100. IVarSetPtr pVS;
  101. pVS = pVarSet;
  102. _bstr_t log = pVS->get(GET_BSTR(DCTVS_Options_Logfile));
  103. err.LogOpen((WCHAR*)log,1);
  104. err.MsgWrite(0,DCT_MSG_MCSPISAG_STARTING);
  105. pVS->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_Gathering_SvcAcct));
  106. ProcessServices(pVS);
  107. pVS->put(GET_BSTR(DCTVS_CurrentOperation),L"");
  108. err.MsgWrite(0,DCT_MSG_MCSPISAG_DONE);
  109. err.LogClose();
  110. return S_OK;
  111. }
  112. STDMETHODIMP CCSvcAcctInfo::GetName(/* [out] */BSTR * name)
  113. {
  114. (*name) = SysAllocString(L"");
  115. return S_OK;
  116. }
  117. STDMETHODIMP CCSvcAcctInfo::GetResultString(/* [in] */IUnknown * pVarSet,/* [out] */ BSTR * text)
  118. {
  119. WCHAR buffer[1000] = L"";
  120. IVarSetPtr pVS;
  121. pVS = pVarSet;
  122. (*text) = SysAllocString(buffer);
  123. return S_OK;
  124. }
  125. STDMETHODIMP CCSvcAcctInfo::StoreResults(/* [in] */IUnknown * pVarSet)
  126. {
  127. IVarSetPtr pVS = pVarSet;
  128. IIManageDBPtr pDatabase;
  129. HRESULT hr;
  130. WCHAR key[200];
  131. _bstr_t service;
  132. _bstr_t account;
  133. _bstr_t computer;
  134. _bstr_t display;
  135. long ndx = 0;
  136. _bstr_t exchangeAccount;
  137. HINSTANCE hLibrary = NULL;
  138. DSCRACKNAMES * DsCrackNames = NULL;
  139. DSFREENAMERESULT * DsFreeNameResult = NULL;
  140. DSBINDFUNC DsBind = NULL;
  141. DSUNBINDFUNC DsUnBind = NULL;
  142. _bstr_t sourceDomainDns = pVS->get(GET_BSTR(DCTVS_Options_SourceDomainDns));
  143. WCHAR * atPtr = NULL;
  144. HANDLE hDs = NULL;
  145. bool bWin2K = false;
  146. //find out the OS version of this system to determine which GetDCName
  147. //function to use
  148. WKSTA_INFO_100 * pInfo = NULL;
  149. NET_API_STATUS nStatus;
  150. nStatus = NetWkstaGetInfo(NULL,100,(LPBYTE*)&pInfo);
  151. if (nStatus == NERR_Success)
  152. {
  153. if ( pInfo->wki100_ver_major > 4 )
  154. bWin2K = true;
  155. NetApiBufferFree(pInfo);
  156. }
  157. computer = pVS->get("LocalServer");
  158. hr = pDatabase.CreateInstance(CLSID_IManageDB);
  159. if ( SUCCEEDED(hr) )
  160. {
  161. // make a pre-pass through the data
  162. do
  163. {
  164. swprintf(key,L"ServiceAccounts.%ld.Service",ndx);
  165. service = pVS->get(key);
  166. swprintf(key,L"ServiceAccounts.%ld.Account",ndx);
  167. account = pVS->get(key);
  168. // make sure the account names are not in UPN format
  169. if ( NULL == wcschr((WCHAR*)account,L'\\') )
  170. {
  171. if (! hDs )
  172. {
  173. if (! hLibrary )
  174. {
  175. hLibrary = LoadLibrary(L"NTDSAPI.DLL");
  176. }
  177. if ( hLibrary )
  178. {
  179. DsBind = (DSBINDFUNC)GetProcAddress(hLibrary,"DsBindW");
  180. DsUnBind = (DSUNBINDFUNC)GetProcAddress(hLibrary,"DsUnBindW");
  181. DsCrackNames = (DSCRACKNAMES *)GetProcAddress(hLibrary,"DsCrackNamesW");
  182. DsFreeNameResult = (DSFREENAMERESULT *)GetProcAddress(hLibrary,"DsFreeNameResultW");
  183. }
  184. if ( DsBind && DsUnBind && DsCrackNames && DsFreeNameResult)
  185. {
  186. hr = (*DsBind)(NULL,(WCHAR*)sourceDomainDns,&hDs);
  187. if ( hr )
  188. {
  189. hDs = NULL;
  190. }
  191. }
  192. }
  193. if ( hDs )
  194. {
  195. PDS_NAME_RESULT pNamesOut = NULL;
  196. WCHAR * pNamesIn[1];
  197. pNamesIn[0] = (WCHAR*)account;
  198. hr = (*DsCrackNames)(hDs,DS_NAME_NO_FLAGS,DS_USER_PRINCIPAL_NAME,DS_NT4_ACCOUNT_NAME,1,pNamesIn,&pNamesOut);
  199. (*DsUnBind)(&hDs);
  200. hDs = NULL;
  201. if ( !hr )
  202. {
  203. if ( pNamesOut->rItems[0].status == DS_NAME_NO_ERROR )
  204. {
  205. account = pNamesOut->rItems[0].pName;
  206. pVS->put(key,account);
  207. }
  208. //if from another domain try connecting to that domain's DC and
  209. //retry DSCrackNames
  210. else if ( pNamesOut->rItems[0].status == DS_NAME_ERROR_DOMAIN_ONLY )
  211. {
  212. WCHAR dc[MAX_PATH];
  213. HRESULT res;
  214. bool bGotDC = false;
  215. //else if win2k, load and use DSGetDCName
  216. if (bWin2K)
  217. {
  218. PDOMAIN_CONTROLLER_INFOW pdomc;
  219. //load DSGetDCName
  220. DSGETDCNAME DsGetDcName = NULL;
  221. DOMAIN_CONTROLLER_INFO * pSrcDomCtrlInfo = NULL;
  222. HMODULE hPro = LoadLibrary(L"NetApi32.dll");
  223. if ( hPro )
  224. DsGetDcName = (DSGETDCNAME)GetProcAddress(hPro, "DsGetDcNameW");
  225. if (DsGetDcName)
  226. {
  227. res = DsGetDcName(NULL,pNamesOut->rItems[0].pDomain,NULL,NULL,DS_DIRECTORY_SERVICE_PREFERRED,&pdomc);
  228. if (res==NERR_Success)
  229. {
  230. bGotDC = true;
  231. safecopy(dc,pdomc->DomainControllerName);
  232. NetApiBufferFree(pdomc);
  233. }
  234. }
  235. }//end if Win2K machine
  236. //if this is an NT 4.0 or earlier machine or DSGetDCName failed,
  237. //use NetGetDCName
  238. if (!bGotDC)
  239. {
  240. LPWSTR pdomc;
  241. res = NetGetDCName(NULL,pNamesOut->rItems[0].pDomain,(LPBYTE *)&pdomc);
  242. if (res==NERR_Success)
  243. {
  244. safecopy(dc,pdomc);
  245. NetApiBufferFree(pdomc);
  246. }
  247. }
  248. if (res==NERR_Success)
  249. {
  250. //bind to that domain DC
  251. hr = (*DsBind)(dc,NULL,&hDs);
  252. if ( !hr )
  253. {
  254. (*DsFreeNameResult)(pNamesOut);//release the old info
  255. pNamesOut = NULL;
  256. //retry DSCrackNames again
  257. hr = (*DsCrackNames)(hDs,DS_NAME_NO_FLAGS,DS_USER_PRINCIPAL_NAME,DS_NT4_ACCOUNT_NAME,1,pNamesIn,&pNamesOut);
  258. if ( !hr )
  259. {
  260. if ( pNamesOut->rItems[0].status == DS_NAME_NO_ERROR )
  261. {
  262. account = pNamesOut->rItems[0].pName;
  263. pVS->put(key,account);
  264. }
  265. }
  266. (*DsUnBind)(&hDs);
  267. hDs = NULL;
  268. }
  269. }
  270. }
  271. if (pNamesOut)
  272. (*DsFreeNameResult)(pNamesOut);
  273. }
  274. }
  275. }
  276. // also, look for the exchange server service account
  277. if ( !UStrICmp(service,EXCHANGE_SERVICE_NAME) )
  278. {
  279. exchangeAccount = account;
  280. break;
  281. }
  282. ndx++;
  283. } while ( service.length() );
  284. ndx = 0;
  285. WCHAR serverFilter[300];
  286. // clear any old entries from the table for this computer
  287. swprintf(serverFilter,L"System = '%ls'",(WCHAR*)computer);
  288. _variant_t Filter = serverFilter;
  289. hr = pDatabase->raw_ClearTable(SysAllocString(L"ServiceAccounts"), Filter);
  290. do
  291. {
  292. swprintf(key,L"ServiceAccounts.%ld.Service",ndx);
  293. service = pVS->get(key);
  294. swprintf(key,L"ServiceAccounts.%ld.DisplayName",ndx);
  295. display = pVS->get(key);
  296. swprintf(key,L"ServiceAccounts.%ld.Account",ndx);
  297. account = pVS->get(key);
  298. if ( service.length() && account.length() )
  299. {
  300. hr = pDatabase->raw_SetServiceAccount(computer,service,display,account);
  301. if ( SUCCEEDED(hr) && !UStrICmp((WCHAR*)account,(WCHAR*)exchangeAccount) )
  302. {
  303. // mark this account to be excluded from the processing
  304. hr = pDatabase->raw_SetServiceAcctEntryStatus(computer,service,account,SvcAcctStatus_NeverAllowUpdate);
  305. }
  306. }
  307. ndx++;
  308. } while ( service.length() );
  309. }
  310. if ( hLibrary )
  311. {
  312. FreeLibrary(hLibrary);
  313. }
  314. return S_OK;
  315. }
  316. STDMETHODIMP CCSvcAcctInfo::ConfigureSettings(/*[in]*/IUnknown * pVarSet)
  317. {
  318. IVarSetPtr pVS = pVarSet;
  319. MessageBox(NULL,L"This is a test",L"McsPISag PlugIn",MB_OK);
  320. return S_OK;
  321. }
  322. void CCSvcAcctInfo::ProcessServices(IVarSet * pVarSet)
  323. {
  324. // Connect to the SCM on the local computer
  325. SC_HANDLE pScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS );
  326. DWORD rc = 0;
  327. WCHAR domain[200];
  328. WKSTA_INFO_100 * info;
  329. // Get the name of the domain that this computer is in, so we can resolve any accounts that are
  330. // specified as .\Account to DOMAIN\account format
  331. rc = NetWkstaGetInfo(NULL,100,(BYTE**)&info);
  332. if ( ! rc )
  333. {
  334. UStrCpy(domain,info->wki100_langroup);
  335. NetApiBufferFree(info);
  336. }
  337. else
  338. {
  339. // if we can't get the domain name, just leave the .
  340. UStrCpy(domain,L".");
  341. }
  342. if ( pScm )
  343. {
  344. // Enumerate the services on the computer
  345. ENUM_SERVICE_STATUS servStatus[1000];
  346. DWORD cbBufSize = (sizeof servStatus);
  347. DWORD cbBytesNeeded = 0;
  348. DWORD nReturned = 0;
  349. DWORD hResume = 0;
  350. WCHAR string[1000];
  351. long count = 0;
  352. if (! EnumServicesStatus(pScm,SERVICE_WIN32,SERVICE_STATE_ALL,servStatus,cbBufSize,&cbBytesNeeded,&nReturned,&hResume) )
  353. {
  354. rc = GetLastError();
  355. err.SysMsgWrite(ErrE,rc,DCT_MSG_SERVICE_ENUM_FAILED_D,rc);
  356. }
  357. else
  358. {
  359. rc = 0;
  360. }
  361. if ( rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA )
  362. {
  363. for ( UINT i = 0 ; i < nReturned ; i++ )
  364. {
  365. SC_HANDLE pService = OpenService(pScm,servStatus[i].lpServiceName,SERVICE_ALL_ACCESS );
  366. BYTE buf[3000];
  367. QUERY_SERVICE_CONFIG * pConfig = (QUERY_SERVICE_CONFIG *)buf;
  368. // BOOL bIncluded = FALSE;
  369. DWORD lenNeeded = 0;
  370. if ( pService )
  371. {
  372. // get the information about this service
  373. if ( QueryServiceConfig(pService,pConfig,sizeof buf, &lenNeeded) )
  374. {
  375. err.MsgWrite(0,DCT_MSG_SERVICE_USES_ACCOUNT_SS,servStatus[i].lpServiceName,pConfig->lpServiceStartName);
  376. // add the account to the list if it is not using LocalSystem
  377. if ( UStrICmp(pConfig->lpServiceStartName,L"LocalSystem"))
  378. {
  379. swprintf(string,L"ServiceAccounts.%ld.Service",count);
  380. pVarSet->put(string,servStatus[i].lpServiceName);
  381. swprintf(string,L"ServiceAccounts.%ld.DisplayName",count);
  382. pVarSet->put(string,servStatus[i].lpDisplayName);
  383. swprintf(string,L"ServiceAccounts.%ld.Account",count);
  384. if ( pConfig->lpServiceStartName[0] == L'.' && pConfig->lpServiceStartName[1] == L'\\' )
  385. {
  386. WCHAR domAcct[500];
  387. // set domAcct to DOMAIN + \Account
  388. UStrCpy(domAcct,domain);
  389. UStrCpy(domAcct+UStrLen(domAcct),pConfig->lpServiceStartName + 1 );
  390. pVarSet->put(string,domAcct);
  391. }
  392. else
  393. {
  394. pVarSet->put(string,pConfig->lpServiceStartName);
  395. }
  396. count++;
  397. }
  398. }
  399. CloseServiceHandle(pService);
  400. }
  401. else
  402. {
  403. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_OPEN_SERVICE_FAILED_SD,servStatus[i].lpServiceName,rc);
  404. }
  405. }
  406. }
  407. CloseServiceHandle(pScm);
  408. }
  409. else
  410. {
  411. rc = GetLastError();
  412. err.SysMsgWrite(ErrE,rc,DCT_MSG_SCM_OPEN_FAILED_D,rc);
  413. }
  414. }