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.

288 lines
8.4 KiB

  1. /*---------------------------------------------------------------------------
  2. File: ComputerPwdAge.cpp
  3. Comments: Implementation of COM object to retrieve password age for computer
  4. accounts (used to detect defunct computer accounts.)
  5. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  6. Proprietary and confidential to Mission Critical Software, Inc.
  7. REVISION LOG ENTRY
  8. Revision By: Christy Boles
  9. Revised on 02/15/99 11:19:31
  10. ---------------------------------------------------------------------------
  11. */
  12. // ComputerPwdAge.cpp : Implementation of CComputerPwdAge
  13. #include "stdafx.h"
  14. #include "WorkObj.h"
  15. #include "PwdAge.h"
  16. #include "Common.hpp"
  17. #include "UString.hpp"
  18. #include "Err.hpp"
  19. #include "CommaLog.hpp"
  20. #include "EaLen.hpp"
  21. //#import "\bin\McsVarSetMin.tlb" no_namespace
  22. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  23. #import "VarSet.tlb" no_namespace rename("property", "aproperty")
  24. #import "DBMgr.tlb" no_namespace, named_guids
  25. #include <lm.h>
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CComputerPwdAge
  28. STDMETHODIMP
  29. CComputerPwdAge::SetDomain(
  30. BSTR domain // in - domain name to examine
  31. )
  32. {
  33. HRESULT hr = S_OK;
  34. DWORD rc;
  35. WCHAR domctrl[LEN_Computer];
  36. if ( UStrICmp(m_Domain,domain) )
  37. {
  38. m_Domain = domain;
  39. rc = GetDomainControllerForDomain(domain,domctrl);
  40. if ( rc )
  41. {
  42. hr = HRESULT_FROM_WIN32(rc);
  43. }
  44. else
  45. {
  46. m_DomainCtrl = domctrl;
  47. }
  48. }
  49. return hr;
  50. }
  51. STDMETHODIMP
  52. CComputerPwdAge::GetPwdAge(
  53. BSTR domain, // in - domain name to examine
  54. BSTR ComputerName, // in - machine name of computer
  55. DWORD * pPwdAge // out- password age in seconds
  56. )
  57. {
  58. HRESULT hr;
  59. DWORD rc;
  60. WCHAR computerAccountName[LEN_Account];
  61. DWORD pwdage = 0;
  62. hr = SetDomain(domain);
  63. if ( SUCCEEDED(hr) )
  64. {
  65. swprintf(computerAccountName,L"%s",ComputerName);
  66. rc = GetSinglePasswordAgeInternal(m_DomainCtrl,computerAccountName,&pwdage);
  67. if ( ! rc )
  68. {
  69. (*pPwdAge) = pwdage;
  70. }
  71. else
  72. {
  73. hr = HRESULT_FROM_WIN32(rc);
  74. }
  75. }
  76. return hr;
  77. }
  78. STDMETHODIMP
  79. CComputerPwdAge::ExportPasswordAge(
  80. BSTR domain, // in - domain to export information from
  81. BSTR filename // in - UNC name of file to write information to
  82. )
  83. {
  84. HRESULT hr;
  85. hr = SetDomain(domain);
  86. if ( SUCCEEDED(hr) )
  87. {
  88. hr = ExportPasswordAgeOlderThan(domain,filename,0);
  89. }
  90. return hr;
  91. }
  92. STDMETHODIMP
  93. CComputerPwdAge::ExportPasswordAgeOlderThan(
  94. BSTR domain, // in - domain to export information from
  95. BSTR filename, // in - filename to write information to
  96. DWORD minAge // in - write only accounts with password age older than minAge
  97. )
  98. {
  99. DWORD rc = 0;
  100. HRESULT hr;
  101. hr = SetDomain(domain);
  102. if ( SUCCEEDED(hr) )
  103. {
  104. rc = ExportPasswordAgeInternal(m_DomainCtrl,filename,minAge,TRUE);
  105. if ( rc )
  106. {
  107. hr = HRESULT_FROM_WIN32(rc);
  108. }
  109. }
  110. return hr;
  111. }
  112. STDMETHODIMP
  113. CComputerPwdAge::ExportPasswordAgeNewerThan(
  114. BSTR domain, // in - domain to export information from
  115. BSTR filename, // in - filename to write information to
  116. DWORD maxAge // in - write only computer accounts with password age less than maxAge
  117. )
  118. {
  119. DWORD rc = 0;
  120. HRESULT hr;
  121. hr = SetDomain(domain);
  122. if ( SUCCEEDED(hr) )
  123. {
  124. rc = ExportPasswordAgeInternal(m_DomainCtrl,filename,maxAge,FALSE);
  125. if ( rc )
  126. {
  127. hr = HRESULT_FROM_WIN32(rc);
  128. }
  129. }
  130. return hr;
  131. }
  132. DWORD // ret- WIN32 error code
  133. CComputerPwdAge::GetDomainControllerForDomain(
  134. WCHAR const * domain, // in - name of domain
  135. WCHAR * domctrl // out- domain controller for domain
  136. )
  137. {
  138. DWORD rc;
  139. WCHAR * result;
  140. rc = NetGetDCName(NULL,domain,(LPBYTE*)&result);
  141. if ( ! rc )
  142. {
  143. wcscpy(domctrl,result);
  144. NetApiBufferFree(result);
  145. }
  146. return rc;
  147. }
  148. DWORD // ret- WIN32 error code
  149. CComputerPwdAge::ExportPasswordAgeInternal(
  150. WCHAR const * domctrl, // in - domain controller to query
  151. WCHAR const * filename, // in - filename to write results to
  152. DWORD minOrMaxAge, // in - optional min or max age to write
  153. BOOL bOld // in - TRUE-Age is min age, copies only old accounts
  154. )
  155. {
  156. DWORD rc = 0;
  157. DWORD nRead;
  158. DWORD nTotal;
  159. DWORD nResume = 0;
  160. DWORD prefmax = 1000;
  161. USER_INFO_11 * buf;
  162. time_t pwdage; // the number of seconds ago that the pwd was last changed
  163. time_t pwdtime; // the time when the pwd was last changed
  164. time_t now; // the current time
  165. CommaDelimitedLog log;
  166. IIManageDBPtr pDB;
  167. WCHAR computerName[LEN_Account];
  168. rc = pDB.CreateInstance(CLSID_IManageDB);
  169. if ( SUCCEEDED(rc) )
  170. {
  171. time(&now);
  172. do
  173. {
  174. rc = NetUserEnum(domctrl,11,FILTER_WORKSTATION_TRUST_ACCOUNT,(LPBYTE*)&buf,prefmax,&nRead,&nTotal,&nResume);
  175. if ( rc && rc != ERROR_MORE_DATA )
  176. break;
  177. for ( UINT i = 0 ; i < nRead ; i++ )
  178. {
  179. pwdage = buf[i].usri11_password_age;
  180. if ( ( pwdage >= (time_t)minOrMaxAge && bOld ) // inactive machines
  181. ||( pwdage <= (time_t)minOrMaxAge && !bOld ) ) // active machines
  182. {
  183. safecopy(computerName,buf[i].usri11_name);
  184. // strip off the $ from the end of the computer account
  185. computerName[UStrLen(computerName)-1] = 0;
  186. // pDB->raw_SavePasswordAge(m_Domain,SysAllocString(computerName),SysAllocString(buf[i].usri11_comment),pwdage);
  187. pDB->raw_SavePasswordAge(m_Domain,SysAllocString(computerName),SysAllocString(buf[i].usri11_comment),(long)pwdage);
  188. pwdtime = now - pwdage;
  189. }
  190. }
  191. NetApiBufferFree(buf);
  192. } while ( rc == ERROR_MORE_DATA );
  193. }
  194. else
  195. {
  196. rc = GetLastError();
  197. }
  198. return rc;
  199. }
  200. DWORD // ret- WIN32 error code
  201. CComputerPwdAge::GetSinglePasswordAgeInternal(
  202. WCHAR const * domctrl, // in - domain controller to query
  203. WCHAR const * computer, // in - name of computer account
  204. DWORD * pwdage // out- password age in seconds
  205. )
  206. {
  207. DWORD rc = 0;
  208. USER_INFO_11 * buf;
  209. rc = NetUserGetInfo(domctrl,computer,11,(LPBYTE*)&buf);
  210. if (! rc )
  211. {
  212. (*pwdage) = buf->usri11_password_age;
  213. NetApiBufferFree(buf);
  214. }
  215. return rc;
  216. }
  217. // ComputerPwdAge worknode
  218. // Retrieves the password age (in seconds) for a computer account in a specified domain
  219. // This can be used to identify defunct computer accounts
  220. //
  221. // VarSet syntax
  222. // Input:
  223. // ComputerPasswordAge.Domain: <DomainName>
  224. // ComputerPasswordAge.Computer: <ComputerName>
  225. // Output:
  226. // ComputerPasswordAge.Seconds : <number>
  227. STDMETHODIMP
  228. CComputerPwdAge::Process(
  229. IUnknown * pWorkItem // in - varset containing settings
  230. )
  231. {
  232. HRESULT hr = S_OK;
  233. IVarSetPtr pVarSet = pWorkItem;
  234. _bstr_t domain;
  235. _bstr_t computer;
  236. DWORD age;
  237. domain = pVarSet->get(L"ComputerPasswordAge.Domain");
  238. computer = pVarSet->get(L"ComputerPasswordAge.Computer");
  239. if ( computer.length() && domain.length() )
  240. {
  241. hr = GetPwdAge(domain,computer,&age);
  242. if ( SUCCEEDED(hr) )
  243. {
  244. pVarSet->put(L"ComputerPasswordAge.Seconds",(LONG)age);
  245. }
  246. }
  247. return hr;
  248. }