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

// UserInfo.cpp: implementation of the CUserInfo class.
// Adapted from the CUserInfo class in the SBS Add User wizard
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <sbs6base.h>
#include "UserInfo.h"
#include <atlbase.h>
#include <comdef.h>
#include <dsgetdc.h>
#include <iads.h> // Must come before adshlp.h
#include <adshlp.h>
#include <lm.h>
#include <emolib.h>
#include <AUsrUtil.h>
#ifndef ASSERT
#define ASSERT assert
#endif
#ifndef WSTRING
typedef std::wstring WSTRING; // Move to sbs6base.h
#endif
#ifndef CHECK_HR
#define CHECK_HR( x ) CHECK_HR_RET( x, _hr );
#define CHECK_HR_RET( x, y ) \
{ \
HRESULT _hr = x; \
if( FAILED(_hr) ) \
{ \
ASSERT( !_T("CHECK_HR_RET() failed. calling TRACE() with HRESULT and statement") ); \
/*::AfxTrace( _T("CHECK_HR_RET() failed, hr == [%d], statement = [%s], returning [%s]"), _hr, #x, #y );*/ \
return y; \
} \
}
#endif // CHECK_HR
// Defines for account flags.
#define PASSWD_NOCHANGE 0x01
#define PASSWD_CANCHANGE 0x02
#define PASSWD_MUSTCHANGE 0x04
#define ACCOUNT_DISABLED 0x10
// ****************************************************************************
// CUserInfo
// ****************************************************************************
// ----------------------------------------------------------------------------
// CUserInfo()
//
// Constructor.
// ----------------------------------------------------------------------------
CUserInfo::CUserInfo()
{
m_dwAccountOptions = 0;
m_bCreateMB = TRUE;
// Store the SBS Server Name
TCHAR szServer[MAX_PATH+1] = {0};
DWORD dwLen = MAX_PATH;
GetComputerName(szServer, &dwLen);
m_csSBSServer = szServer;
// Get domain controller name
PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
HRESULT hr = DsGetDcName (NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED, &DomainControllerInfo);
ASSERT(hr == S_OK && "DsGetDcName failed");
// cache the domain
if ( DomainControllerInfo )
{
m_csDomainName = DomainControllerInfo->DomainName;
// free memory
NetApiBufferFree (DomainControllerInfo);
}
// convert from '.' separated names to Dc=xxx,DC=yyy,... format
WSTRING tmpDomain = m_csDomainName;
while ( !tmpDomain.empty() )
{
int nPos = tmpDomain.find(_T("."));
if ( nPos == WSTRING::npos )
{
nPos = tmpDomain.length();
}
if ( !m_csFQDomainName.empty() )
{
m_csFQDomainName += _T(",");
}
m_csFQDomainName += _T("DC=");
m_csFQDomainName += tmpDomain.substr( 0, nPos );
tmpDomain.erase( 0, nPos + 1 );
}
}
CUserInfo::~CUserInfo()
{
for ( int i = 0 ; i < m_csPasswd.length() ; i++ )
m_csPasswd[i] = '\0' ;
if ( 0 < m_csPasswd.length()) m_csPasswd[0] = NULL ;
// Make sure that the last operation on the string isn't the origonal assignment.
// The compiler will optimize the last statement out
// if it is an assignment that doesn't get used.
}
// ----------------------------------------------------------------------------
// CreateAccount()
//
// Makes a new user account in the Active Directory.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::CreateAccount()
{
HRESULT hr = S_OK;
BOOL bRO = TRUE;
_bstr_t _bstr;
_bstr_t _bstrClass;
_bstr_t _bstrProperty;
_variant_t _vTmpVal;
CComPtr<IADsContainer> spADsContainer = NULL;
// Bind to the container.
WSTRING csLdapUserOU;
if ( _tcsstr( m_csUserOU.c_str(), L"LDAP://") )
csLdapUserOU = m_csUserOU.c_str();
else
{
if ( m_csUserOU.empty() )
{
csLdapUserOU = L"LDAP://CN=Users," + m_csFQDomainName;
m_csUserOU = csLdapUserOU;
}
else
csLdapUserOU = L"LDAP://" + m_csUserOU;
}
hr = ::ADsGetObject( csLdapUserOU.c_str(), IID_IADsContainer, (VOID**) &spADsContainer );
if ( FAILED(hr) )
return(hr);
// Create the user account.
CComPtr<IDispatch> spDisp = NULL;
_bstr = m_csUserCN.c_str();
_bstrClass = L"user";
hr = spADsContainer->Create( _bstrClass, _bstr, &spDisp );
if ( FAILED(hr) )
{
ASSERT(FALSE);
return(hr);
}
// m_pCmt->m_csADName = L"LDAP://";
// m_pCmt->m_csADName += m_csUserCN;
// m_pCmt->m_csADName += L",";
// m_pCmt->m_csADName += (LPCTSTR)csLdapUserOU+7;
// Use this new account and set it's properties (e.g. first name, home folder, etc.).
CComQIPtr<IADsUser, &IID_IADsUser> spADsUserObj(spDisp);
if ( !spADsUserObj )
{
ASSERT(FALSE);
return(E_FAIL);
}
TCHAR szTmp[MAX_PATH*4] = {0};
LdapToDCName( csLdapUserOU.c_str(), szTmp, (MAX_PATH*4));
WSTRING csUserPrincName = m_csUserName;
csUserPrincName += L"@";
csUserPrincName += szTmp;
EmailAddr = csUserPrincName;
// Username:
_vTmpVal.Clear();
_vTmpVal = ( csUserPrincName.c_str() );
_bstrProperty = L"userPrincipalName";
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
return(E_FAIL);
}
// Pre-Win2000 username:
_vTmpVal.Clear();
_vTmpVal = ( _tcslen( m_csUserNamePre2k.c_str() ) ? m_csUserNamePre2k.c_str() : m_csUserName.c_str() );
_bstrProperty = L"sAMAccountName";
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
return(E_FAIL);
}
// Use UserName instead
_bstr = m_csUserName.c_str();
if ( FAILED( spADsUserObj->put_FullName( _bstr )))
{
ASSERT(FALSE);
return(E_FAIL);
}
// Display Name
_vTmpVal.Clear();
_vTmpVal = m_csUserName.c_str();
_bstrProperty = L"displayName";
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
return(E_FAIL);
}
// Commit this information to the AD.
CHECK_HR( spADsUserObj->SetInfo() );
// Password expired?
_vTmpVal.Clear();
V_VT( &_vTmpVal ) = VT_I4;
V_I4( &_vTmpVal ) = (m_dwAccountOptions & PASSWD_MUSTCHANGE) ? 0 : -1;
_bstrProperty = L"pwdLastSet";
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
}
// Account disabled?
_vTmpVal.Clear();
_bstrProperty = L"userAccountControl";
if ( FAILED(spADsUserObj->Get( _bstrProperty, &_vTmpVal )) )
{
ASSERT(FALSE);
}
else
{
_vTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
if ( m_dwAccountOptions & ACCOUNT_DISABLED ) // Do we want to disable the account?
_vTmpVal.lVal |= UF_ACCOUNTDISABLE;
else
_vTmpVal.lVal &= ~UF_ACCOUNTDISABLE; // ..not disable the account.
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
}
}
// Set the password.
hr = SetPasswd();
if ( FAILED( hr ))
{
// m_pCmt->SetErrorResults(ERROR_PASSWORD);
_vTmpVal.Clear();
_bstrProperty = L"userAccountControl";
if ( FAILED(spADsUserObj->Get( _bstrProperty, &_vTmpVal )) )
{
ASSERT(FALSE);
}
else
{
_vTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
_vTmpVal.lVal |= UF_ACCOUNTDISABLE; // Disable the account.
if ( FAILED(spADsUserObj->Put( _bstrProperty, _vTmpVal )) )
{
ASSERT(FALSE);
}
}
// Commit this information to the AD.
if ( FAILED( spADsUserObj->SetInfo() ))
{
ASSERT(FALSE);
}
return hr;
}
// Commit this information to the AD.
hr = spADsUserObj->SetInfo();
if ( FAILED( hr ))
{
ASSERT(FALSE);
}
return hr;
}
// ----------------------------------------------------------------------------
// CreateMailbox()
//
// Makes a new exchange mailbox for the user.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::CreateMailbox()
{
HRESULT hr = S_OK;
CComVariant _vTmpVal;
CComPtr<IADsContainer> spADsContainer = NULL;
_bstr_t _bstr;
_bstr_t _bstrClass;
if ( 0 == m_csEXHomeMDB.length() )
{
hr = GetMDBPath( m_csEXHomeMDB );
if FAILED( hr )
return hr;
}
// Do we even need to run?
if ( 0 == m_csEXHomeMDB.length() || 0 == m_csEXAlias.length() )
return(hr);
// Bind to the container.
WSTRING csLdapUserOU = L"LDAP://";
if ( _tcsstr( m_csUserOU.c_str(), L"LDAP://") )
csLdapUserOU = m_csUserOU.c_str();
else
{
if ( m_csUserOU.empty() )
{
csLdapUserOU = L"LDAP://CN=Users," + m_csFQDomainName;
m_csUserOU = csLdapUserOU;
}
else
csLdapUserOU = L"LDAP://" + m_csUserOU;
}
hr = ::ADsGetObject( csLdapUserOU.c_str(), IID_IADsContainer, (VOID**) &spADsContainer );
if ( FAILED(hr) || !spADsContainer )
{
ASSERT(FALSE);
return(hr);
}
// Open the user account.
CComPtr<IDispatch> spDisp = NULL;
_bstr = m_csUserCN.c_str();
_bstrClass = L"user";
hr = spADsContainer->GetObject( _bstrClass, _bstr, &spDisp );
// if ( !spDisp ) // If the user doesn't exist, create it.
// hr = spADsContainer->Create( L"user", (LPWSTR)(LPCWSTR)m_csUserCN, &spDisp );
// return(hr); // Let's just return.. maybe we'll want to change to create later?
if ( !spDisp ) // Was there a problem getting the account (either existing or new)?
{
ASSERT(FALSE);
return(hr);
}
// Get a handle on the user.
CComPtr<IADsUser> spADsUserObj;
hr = spDisp->QueryInterface ( __uuidof(IADsUser), (void**)&spADsUserObj );
if ( FAILED(hr) || !spADsUserObj ) // Was there a problem getting the user object?
{
ASSERT(FALSE);
return(hr);
}
// Get the interface needed to deal with the mailbox.
CComPtr<IMailboxStore> spMailboxStore;
hr = spADsUserObj->QueryInterface ( __uuidof(IMailboxStore), (void**)&spMailboxStore );
if ( FAILED(hr) || !spMailboxStore ) // Was there a problem getting the mailbox store interface?
{
ASSERT(FALSE);
return(hr);
}
// if ( SUCCEEDED( hr ) )
// { // Need to set the mailNickname first otherwise the alias will always be manufactured from the name.
// m_csEXAlias = CreateEmailName( m_csEXAlias );
// m_csEXAlias.TrimLeft();
// m_csEXAlias.TrimRight();
// if ( 0 == m_csEXAlias.length( ) )
// {
// m_csEXAlias.LoadString( IDS_NOLOC_USEREMAILALIAS );
// }
//
// CComBSTR bszTmp = (LPCTSTR) m_csEXAlias;
// VARIANT v;
//
// VariantInit( &v );
// V_VT( &v ) = VT_BSTR;
// V_BSTR( &v ) = bszTmp;
// hr = spADsUserObj->Put( L"mailNickname", v );
// }
if ( SUCCEEDED( hr ) )
{ // Create the mailbox.
WSTRING csLdapHomeMDB = L"LDAP://";
csLdapHomeMDB += m_csEXHomeMDB;
_bstr = csLdapHomeMDB.c_str();
hr = spMailboxStore->CreateMailbox( _bstr );
if ( hr == S_OK ) // If it's a new mailbox, set the info.
{
hr = spADsUserObj->SetInfo();
}
if ( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS ) // If it already exists, just move on.
{
hr = S_OK;
}
}
if ( FAILED(hr) ) // Was there a problem?
{
ASSERT(FALSE);
return(hr);
}
return(hr);
}
// ----------------------------------------------------------------------------
// SetPasswd()
// ----------------------------------------------------------------------------
HRESULT CUserInfo::SetPasswd()
{
HRESULT hr = S_OK;
WSTRING csUser = _T("LDAP://");
if ( _tcsstr( m_csUserOU.c_str(), _T("LDAP://")) )
{
csUser += m_csUserCN;
csUser += _T(",");
csUser += m_csUserOU.c_str() + 7;
}
else
{
csUser += m_csUserCN;
csUser += _T(",");
csUser += m_csUserOU.c_str();
}
// Now csUser is something like "LDAP://CN=JohnDoe,DC=Blah"
CComPtr<IADsUser> spDS = NULL;
hr = ::ADsGetObject( csUser.c_str(), IID_IADsUser, (void**)&spDS );
CHECK_HR(hr);
// Set the password.
if ( m_csPasswd.length() ) // Only if there IS a passwd!
{
CComBSTR bszPasswd = m_csPasswd.c_str();
hr = spDS->SetPassword(bszPasswd);
CHECK_HR(hr);
}
// Allow change?
if ( m_dwAccountOptions & PASSWD_NOCHANGE )
{
CComVariant vaTmpVal;
CComBSTR bstrProp = _T("UserFlags");
vaTmpVal.Clear();
hr = spDS->Get( bstrProp, &vaTmpVal );
CHECK_HR(hr);
vaTmpVal.lVal |= UF_PASSWD_CANT_CHANGE;
hr = spDS->Put( bstrProp, vaTmpVal );
CHECK_HR(hr);
}
// SetInfo only if we actually changed anything.
if ( ( m_csPasswd.length()) || // Did we mess with the passwd?
( m_dwAccountOptions & PASSWD_NOCHANGE ) ) // Did we make it unable to change?
{
hr = spDS->SetInfo(); // If either, then set the new info.
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////////////
// SetUserName
// Set the user name and dependant member variables (m_csUserCN, m_csEXAlias)
/////////////////////////////////////////////////////////////////////////////////////
HRESULT CUserInfo::SetUserName( LPCTSTR szUserName )
{
m_csUserName = szUserName;
m_csUserCN = L"CN=" + m_csUserName;
m_csEXAlias = szUserName;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////////////
// SetPassword
// Set the Password
/////////////////////////////////////////////////////////////////////////////////////
HRESULT CUserInfo::SetPassword( LPCTSTR szPassword )
{
m_csPasswd = szPassword;
return S_OK;
}