289 lines
8.4 KiB
C++
289 lines
8.4 KiB
C++
/*---------------------------------------------------------------------------
|
|
File: ComputerPwdAge.cpp
|
|
|
|
Comments: Implementation of COM object to retrieve password age for computer
|
|
accounts (used to detect defunct computer accounts.)
|
|
|
|
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 02/15/99 11:19:31
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
// ComputerPwdAge.cpp : Implementation of CComputerPwdAge
|
|
#include "stdafx.h"
|
|
#include "WorkObj.h"
|
|
#include "PwdAge.h"
|
|
#include "Common.hpp"
|
|
#include "UString.hpp"
|
|
#include "Err.hpp"
|
|
#include "CommaLog.hpp"
|
|
#include "EaLen.hpp"
|
|
|
|
//#import "\bin\McsVarSetMin.tlb" no_namespace
|
|
//#import "\bin\DBManager.tlb" no_namespace, named_guids
|
|
#import "VarSet.tlb" no_namespace rename("property", "aproperty")
|
|
#import "DBMgr.tlb" no_namespace, named_guids
|
|
|
|
#include <lm.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CComputerPwdAge
|
|
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::SetDomain(
|
|
BSTR domain // in - domain name to examine
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
WCHAR domctrl[LEN_Computer];
|
|
|
|
if ( UStrICmp(m_Domain,domain) )
|
|
{
|
|
m_Domain = domain;
|
|
|
|
rc = GetDomainControllerForDomain(domain,domctrl);
|
|
|
|
if ( rc )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
else
|
|
{
|
|
m_DomainCtrl = domctrl;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::GetPwdAge(
|
|
BSTR domain, // in - domain name to examine
|
|
BSTR ComputerName, // in - machine name of computer
|
|
DWORD * pPwdAge // out- password age in seconds
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD rc;
|
|
WCHAR computerAccountName[LEN_Account];
|
|
DWORD pwdage = 0;
|
|
|
|
hr = SetDomain(domain);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
swprintf(computerAccountName,L"%s",ComputerName);
|
|
rc = GetSinglePasswordAgeInternal(m_DomainCtrl,computerAccountName,&pwdage);
|
|
if ( ! rc )
|
|
{
|
|
(*pPwdAge) = pwdage;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::ExportPasswordAge(
|
|
BSTR domain, // in - domain to export information from
|
|
BSTR filename // in - UNC name of file to write information to
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = SetDomain(domain);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = ExportPasswordAgeOlderThan(domain,filename,0);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::ExportPasswordAgeOlderThan(
|
|
BSTR domain, // in - domain to export information from
|
|
BSTR filename, // in - filename to write information to
|
|
DWORD minAge // in - write only accounts with password age older than minAge
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
HRESULT hr;
|
|
|
|
hr = SetDomain(domain);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
rc = ExportPasswordAgeInternal(m_DomainCtrl,filename,minAge,TRUE);
|
|
if ( rc )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::ExportPasswordAgeNewerThan(
|
|
BSTR domain, // in - domain to export information from
|
|
BSTR filename, // in - filename to write information to
|
|
DWORD maxAge // in - write only computer accounts with password age less than maxAge
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
HRESULT hr;
|
|
|
|
hr = SetDomain(domain);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
rc = ExportPasswordAgeInternal(m_DomainCtrl,filename,maxAge,FALSE);
|
|
if ( rc )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
return hr;
|
|
|
|
}
|
|
|
|
DWORD // ret- WIN32 error code
|
|
CComputerPwdAge::GetDomainControllerForDomain(
|
|
WCHAR const * domain, // in - name of domain
|
|
WCHAR * domctrl // out- domain controller for domain
|
|
)
|
|
{
|
|
DWORD rc;
|
|
WCHAR * result;
|
|
|
|
rc = NetGetDCName(NULL,domain,(LPBYTE*)&result);
|
|
if ( ! rc )
|
|
{
|
|
wcscpy(domctrl,result);
|
|
NetApiBufferFree(result);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
DWORD // ret- WIN32 error code
|
|
CComputerPwdAge::ExportPasswordAgeInternal(
|
|
WCHAR const * domctrl, // in - domain controller to query
|
|
WCHAR const * filename, // in - filename to write results to
|
|
DWORD minOrMaxAge, // in - optional min or max age to write
|
|
BOOL bOld // in - TRUE-Age is min age, copies only old accounts
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
DWORD nRead;
|
|
DWORD nTotal;
|
|
DWORD nResume = 0;
|
|
DWORD prefmax = 1000;
|
|
USER_INFO_11 * buf;
|
|
time_t pwdage; // the number of seconds ago that the pwd was last changed
|
|
time_t pwdtime; // the time when the pwd was last changed
|
|
time_t now; // the current time
|
|
CommaDelimitedLog log;
|
|
IIManageDBPtr pDB;
|
|
WCHAR computerName[LEN_Account];
|
|
|
|
rc = pDB.CreateInstance(CLSID_IManageDB);
|
|
if ( SUCCEEDED(rc) )
|
|
{
|
|
|
|
time(&now);
|
|
do
|
|
{
|
|
rc = NetUserEnum(domctrl,11,FILTER_WORKSTATION_TRUST_ACCOUNT,(LPBYTE*)&buf,prefmax,&nRead,&nTotal,&nResume);
|
|
if ( rc && rc != ERROR_MORE_DATA )
|
|
break;
|
|
for ( UINT i = 0 ; i < nRead ; i++ )
|
|
{
|
|
pwdage = buf[i].usri11_password_age;
|
|
if ( ( pwdage >= (time_t)minOrMaxAge && bOld ) // inactive machines
|
|
||( pwdage <= (time_t)minOrMaxAge && !bOld ) ) // active machines
|
|
{
|
|
safecopy(computerName,buf[i].usri11_name);
|
|
// strip off the $ from the end of the computer account
|
|
computerName[UStrLen(computerName)-1] = 0;
|
|
// pDB->raw_SavePasswordAge(m_Domain,SysAllocString(computerName),SysAllocString(buf[i].usri11_comment),pwdage);
|
|
pDB->raw_SavePasswordAge(m_Domain,SysAllocString(computerName),SysAllocString(buf[i].usri11_comment),(long)pwdage);
|
|
|
|
pwdtime = now - pwdage;
|
|
}
|
|
}
|
|
NetApiBufferFree(buf);
|
|
|
|
} while ( rc == ERROR_MORE_DATA );
|
|
|
|
}
|
|
else
|
|
{
|
|
rc = GetLastError();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD // ret- WIN32 error code
|
|
CComputerPwdAge::GetSinglePasswordAgeInternal(
|
|
WCHAR const * domctrl, // in - domain controller to query
|
|
WCHAR const * computer, // in - name of computer account
|
|
DWORD * pwdage // out- password age in seconds
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
USER_INFO_11 * buf;
|
|
|
|
rc = NetUserGetInfo(domctrl,computer,11,(LPBYTE*)&buf);
|
|
|
|
if (! rc )
|
|
{
|
|
(*pwdage) = buf->usri11_password_age;
|
|
NetApiBufferFree(buf);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
// ComputerPwdAge worknode
|
|
// Retrieves the password age (in seconds) for a computer account in a specified domain
|
|
// This can be used to identify defunct computer accounts
|
|
//
|
|
// VarSet syntax
|
|
// Input:
|
|
// ComputerPasswordAge.Domain: <DomainName>
|
|
// ComputerPasswordAge.Computer: <ComputerName>
|
|
// Output:
|
|
// ComputerPasswordAge.Seconds : <number>
|
|
|
|
STDMETHODIMP
|
|
CComputerPwdAge::Process(
|
|
IUnknown * pWorkItem // in - varset containing settings
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IVarSetPtr pVarSet = pWorkItem;
|
|
_bstr_t domain;
|
|
_bstr_t computer;
|
|
DWORD age;
|
|
|
|
domain = pVarSet->get(L"ComputerPasswordAge.Domain");
|
|
computer = pVarSet->get(L"ComputerPasswordAge.Computer");
|
|
if ( computer.length() && domain.length() )
|
|
{
|
|
hr = GetPwdAge(domain,computer,&age);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
pVarSet->put(L"ComputerPasswordAge.Seconds",(LONG)age);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|