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.
 
 
 
 
 
 

767 lines
24 KiB

// AccntCmt.cpp : Implementation of CAddUser_AccntCommit
#include "stdafx.h"
#include "AU_Accnt.h"
#include "AccntCmt.h"
#include <dsgetdc.h>
#include <lm.h>
#include <lmshare.h>
#include <Aclapi.h>
#include <atlcom.h>
// ldap/adsi includes
#include <iads.h>
#include <adshlp.h>
#include <adsiid.h>
#include <proputil.h>
#include <CreateEmailName.h>
#include <P3admin.h>
#include <CheckUser.h>
// POP3 Defines
#define SZ_AUTH_ID_MD5_HASH _T("c395e20c-2236-4af7-b736-54fad07dc526")
// Defines for account flags.
#define PASSWD_NOCHANGE 0x01
#define PASSWD_CANCHANGE 0x02
#define PASSWD_MUSTCHANGE 0x04
#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") ); \
return y; \
} \
}
#endif // CHECK_HRhr;
// ****************************************************************************
// CAddUser_AccntCommit
// ****************************************************************************
// ----------------------------------------------------------------------------
// WriteErrorResults()
// ----------------------------------------------------------------------------
HRESULT CAddUser_AccntCommit::WriteErrorResults( IPropertyPagePropertyBag* pPPPBag )
{
// ------------------------------------------------------------------------
// Write the the values to the property bag.
// ------------------------------------------------------------------------
if( FAILED(WriteInt4 ( pPPPBag, PROP_ACCNT_ERROR_CODE_GUID_STRING, m_dwErrCode, FALSE )) )
{
_ASSERT(FALSE);
}
if( FAILED(WriteString( pPPPBag, PROP_ACCNT_ERROR_STR_GUID_STRING, m_csErrStr, FALSE )) )
{
_ASSERT(FALSE);
}
return S_OK;
}
// ----------------------------------------------------------------------------
// SetErrCode()
// ----------------------------------------------------------------------------
void CAddUser_AccntCommit::SetErrCode( DWORD dwCode )
{
m_dwErrCode |= dwCode;
return;
}
// ----------------------------------------------------------------------------
// SetErrorResults()
// ----------------------------------------------------------------------------
HRESULT CAddUser_AccntCommit::SetErrorResults( DWORD dwErrType, BOOL bPOP3 /* = FALSE */ )
{
SetErrCode(dwErrType);
CString csTemp;
switch( dwErrType )
{
case ERROR_CREATION:
case ERROR_PROPERTIES:
{
m_csErrStr.LoadString(IDS_ERROR_CREATING_USER);
break;
}
case ERROR_MAILBOX:
{
csTemp.LoadString( IDS_ERROR_POP3MAILBOX);
m_csErrStr += csTemp;
break;
}
case ERROR_PASSWORD:
{
csTemp.LoadString(IDS_ERROR_PASSWORD);
m_csErrStr += csTemp;
break;
}
case ERROR_DUPE:
{
csTemp.LoadString(IDS_ERROR_DUPLICATE);
m_csErrStr += csTemp;
break;
}
case ERROR_MEMBERSHIPS:
{
csTemp.LoadString(IDS_ERROR_MEMBERSHIP);
m_csErrStr += csTemp;
break;
}
default :
{
m_dwErrCode = 0;
m_csErrStr = _T("");
break;
}
}
return S_OK;
}
// ----------------------------------------------------------------------------
// Commit()
// ----------------------------------------------------------------------------
HRESULT CAddUser_AccntCommit::Commit( IDispatch* pdispPPPBag )
{
HRESULT hr = S_OK;
HRESULT hrAdmin = IsUserInGroup( DOMAIN_ALIAS_RID_ADMINS );
if( hrAdmin != S_OK )
{
return E_ACCESSDENIED;
}
CComPtr<IPropertyPagePropertyBag> spPPPBag = NULL;
hr = pdispPPPBag->QueryInterface( __uuidof(IPropertyPagePropertyBag), (void**)&spPPPBag );
if ( !spPPPBag )
return hr;
BOOL bRO = FALSE;
BOOL bPOP3 = FALSE;
ReadBool( spPPPBag, PROP_POP3_CREATE_MB_GUID_STRING, &bPOP3, &bRO );
// Reset the error conditions
SetErrorResults( 0 );
// ------------------------------------------------------------------------
// Read in the values from the property bag.
// ------------------------------------------------------------------------
CUserInfo cUInfo( spPPPBag, this );
// ------------------------------------------------------------------------
// Use those values to do something.
// ------------------------------------------------------------------------
hr = cUInfo.CreateAccount();
if( FAILED(hr) )
{
if( !(m_dwErrCode & (ERROR_PASSWORD | ERROR_MEMBERSHIPS)) )
{
if ( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS )
{
SetErrorResults(ERROR_DUPE);
}
else
{
SetErrorResults(ERROR_CREATION);
}
WriteErrorResults(spPPPBag);
return E_FAIL;
}
}
hr = cUInfo.CreateMailbox();
if( FAILED(hr) )
{
SetErrorResults(ERROR_MAILBOX, bPOP3);
}
if( m_dwErrCode )
{
hr = E_FAIL;
WriteErrorResults(spPPPBag);
}
return hr;
}
// ----------------------------------------------------------------------------
// Revert()
// ----------------------------------------------------------------------------
HRESULT CAddUser_AccntCommit::Revert()
{
NET_API_STATUS nApi;
HRESULT hr = S_OK;
CComPtr<IADs> spUser = NULL;
CComPtr<IADsDeleteOps> spDelOps = NULL;
// Remove the entry-point in the AD if we made one.
if( m_csADName != _T("") )
{
CHECK_HR( ::ADsGetObject( m_csADName, IID_IADs, (void**)&spUser ) );
// Delete the User
hr = spUser->QueryInterface( IID_IADsDeleteOps, (void**)&spDelOps );
if( SUCCEEDED(hr) && spDelOps )
{
hr = spDelOps->DeleteObject( 0 );
}
}
return hr;
}
// ****************************************************************************
// CUserInfo
// ****************************************************************************
// ----------------------------------------------------------------------------
// CUserInfo()
//
// Constructor.
// ----------------------------------------------------------------------------
CUserInfo::CUserInfo( IPropertyPagePropertyBag* pPPPBag, CAddUser_AccntCommit* pCmt )
{
_ASSERT(pCmt);
m_pCmt = pCmt;
m_pPPPBag = pPPPBag;
m_dwAccountOptions = 0;
m_bPOP3 = FALSE;
// Get domain controller name
PDOMAIN_CONTROLLER_INFO pDCI = NULL;
DWORD dwErr = DsGetDcName( NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED, &pDCI );
// cache the domain
if( (dwErr == NO_ERROR) && pDCI )
{
m_csDomainName = pDCI->DomainName;
NetApiBufferFree( pDCI );
pDCI = NULL;
}
// convert from '.' separated names to Dc=xxx,DC=yyy,... format
m_csFQDomainName = GetDomainPath( m_csDomainName ).c_str();
ReadBag( );
}
// ----------------------------------------------------------------------------
// ReadBag()
//
// Read in the values from the property bag into the member variables.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::ReadBag()
{
HRESULT hr = S_OK;
if ( !m_pPPPBag ) // Make sure we have the property bag to read from.
return(E_FAIL); // If not, fail.
BOOL bRO;
// User Properties
ReadString( m_pPPPBag, PROP_USEROU_GUID_STRING, m_csUserOU, &bRO );
ReadString( m_pPPPBag, PROP_USERNAME_GUID_STRING, m_csUserName, &bRO );
ReadString( m_pPPPBag, PROP_USER_CN, m_csUserCN, &bRO );
ReadString( m_pPPPBag, PROP_PASSWD_GUID_STRING, m_csPasswd, &bRO );
ReadInt4 ( m_pPPPBag, PROP_ACCOUNT_OPT_GUID_STRING, (LONG*)&m_dwAccountOptions, &bRO );
ReadString( m_pPPPBag, PROP_USERNAME_PRE2K_GUID_STRING, m_csUserNamePre2k, &bRO );
ReadString( m_pPPPBag, PROP_FIRSTNAME_GUID_STRING, m_csFirstName, &bRO );
ReadString( m_pPPPBag, PROP_LASTNAME_GUID_STRING, m_csLastName, &bRO );
ReadString( m_pPPPBag, PROP_TELEPHONE_GUID_STRING, m_csTelephone, &bRO );
ReadString( m_pPPPBag, PROP_OFFICE_GUID_STRING, m_csOffice, &bRO );
ReadString( m_pPPPBag, PROP_DESCRIPTION_GUID_STRING, m_csDesc, &bRO );
ReadString( m_pPPPBag, PROP_LOGON_DNS, m_csLogonDns, &bRO );
// Mailbox properties
ReadBool ( m_pPPPBag, PROP_POP3_CREATE_MB_GUID_STRING, &m_bPOP3, &bRO );
ReadString( m_pPPPBag, PROP_EX_ALIAS_GUID_STRING, m_csEXAlias, &bRO );
ReadString( m_pPPPBag, PROP_EX_SERVER_GUID_STRING, m_csEXServer, &bRO );
ReadString( m_pPPPBag, PROP_EX_HOMESERVER_GUID_STRING, m_csEXHomeServer, &bRO );
ReadString( m_pPPPBag, PROP_EX_HOME_MDB_GUID_STRING, m_csEXHomeMDB, &bRO );
// Escape the User's Name
m_csUserCN = EscapeString(((LPCTSTR)m_csUserCN+3), 2);
m_csUserCN = _T("CN=") + m_csUserCN;
// Let's figure out the fullname right here and fill in the m_csFullName variable.
m_csFirstName.TrimLeft ( );
m_csFirstName.TrimRight( );
m_csLastName.TrimLeft ( );
m_csLastName.TrimRight ( );
m_csFullName.FormatMessage(IDS_FULLNAME_FORMAT_STR, (LPCTSTR)m_csFirstName, (LPCTSTR)m_csLastName);
m_csFullName.TrimLeft ( );
m_csFullName.TrimRight ( );
return(hr);
}
// ----------------------------------------------------------------------------
// CreateAccount()
//
// Makes a new user account in the Active Directory.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::CreateAccount( )
{
HRESULT hr = S_OK;
BOOL bRO = TRUE;
CComVariant vaTmpVal;
CComBSTR bstrProp;
CComPtr<IADsContainer> spADsContainer = NULL;
// Bind to the container.
CString csLdapUserOU = _T("LDAP://");
if( _tcsstr( (LPCTSTR)m_csUserOU, _T("LDAP://") ) )
{
csLdapUserOU = m_csUserOU;
}
else
{
csLdapUserOU += m_csUserOU;
}
hr = ::ADsGetObject( (LPWSTR)(LPCWSTR)csLdapUserOU, IID_IADsContainer, (VOID**) &spADsContainer );
CHECK_HR(hr);
// Create the user account.
CComPtr<IDispatch> spDisp = NULL;
bstrProp = _T("user");
CComBSTR bstrValue = (LPCWSTR)m_csUserCN;
hr = spADsContainer->Create( bstrProp, bstrValue, &spDisp );
CHECK_HR(hr);
m_pCmt->m_csADName = _T("LDAP://");
m_pCmt->m_csADName += m_csUserCN;
m_pCmt->m_csADName += _T(",");
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( (LPCTSTR)csLdapUserOU, szTmp, (MAX_PATH*4) );
CString csUserPrincName = m_csUserName;
csUserPrincName += _T("@");
csUserPrincName += szTmp;
// Username:
vaTmpVal.Clear();
vaTmpVal = ((LPCWSTR)csUserPrincName);
bstrProp = _T("userPrincipalName");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
// Pre-Win2000 username:
vaTmpVal.Clear();
vaTmpVal = ((LPCWSTR)m_csUserNamePre2k);
bstrProp = _T("sAMAccountName");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
// First name:
if( m_csFirstName.GetLength() )
{
bstrProp = (LPCWSTR)m_csFirstName;
CHECK_HR( spADsUserObj->put_FirstName( bstrProp ) );
}
// Last name:
if( m_csLastName.GetLength() )
{
bstrProp = (LPCWSTR)m_csLastName;
CHECK_HR( spADsUserObj->put_LastName( bstrProp ) );
}
if( m_csFullName.GetLength() )
{
// Full name:
bstrProp = (LPCWSTR)m_csFullName;
CHECK_HR( spADsUserObj->put_FullName( bstrProp ) );
// Display Name
vaTmpVal.Clear();
vaTmpVal = (LPCWSTR)m_csFullName;
bstrProp = _T("displayName");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
}
// Telephone number
if( _tcslen((LPCTSTR)m_csTelephone) )
{
vaTmpVal.Clear();
vaTmpVal = (LPCWSTR)m_csTelephone;
bstrProp = _T("telephoneNumber");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
}
// Office Location
if( _tcslen((LPCTSTR)m_csOffice) )
{
vaTmpVal.Clear();
vaTmpVal = (LPCWSTR)m_csOffice;
bstrProp = _T("physicalDeliveryOfficeName");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
}
// Commit this information to the AD.
CHECK_HR( spADsUserObj->SetInfo() );
// Password expired?
vaTmpVal.Clear();
vaTmpVal = (m_dwAccountOptions & PASSWD_MUSTCHANGE) ? (INT) 0 : (INT) -1;
bstrProp = _T("pwdLastSet");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
// Account disabled?
vaTmpVal.Clear();
bstrProp = _T("userAccountControl");
CHECK_HR( spADsUserObj->Get( bstrProp, &vaTmpVal ) );
vaTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
vaTmpVal.lVal &= ~UF_ACCOUNTDISABLE; // Do not disable the account.
bstrProp = _T("userAccountControl");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
// Set the password.
if( FAILED(SetPasswd()) )
{
m_pCmt->SetErrorResults( ERROR_PASSWORD );
vaTmpVal.Clear();
bstrProp = _T("userAccountControl");
CHECK_HR( spADsUserObj->Get( bstrProp, &vaTmpVal ) );
vaTmpVal.lVal &= ~UF_PASSWD_NOTREQD; // Make passwd required.
vaTmpVal.lVal |= UF_ACCOUNTDISABLE; // Disable the account.
bstrProp = _T("userAccountControl");
CHECK_HR( spADsUserObj->Put( bstrProp, vaTmpVal ) );
// Commit this information to the AD.
CHECK_HR( spADsUserObj->SetInfo() );
return E_FAIL;
}
// Commit this information to the AD.
CHECK_HR( spADsUserObj->SetInfo() );
// Join to Domain Users
if ( FAILED(JoinToDomainUsers()) )
{
m_pCmt->SetErrorResults( ERROR_MEMBERSHIPS );
return E_FAIL;
}
return S_OK;
}
// ----------------------------------------------------------------------------
// CreateMailbox()
//
// Makes a new mailbox for the user.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::CreateMailbox()
{
HRESULT hr = S_OK;
if( m_bPOP3 )
{
hr = CreatePOP3Mailbox();
}
return hr;
}
// ----------------------------------------------------------------------------
// CreatePOP3Mailbox()
//
// Makes a new (MS) POP3 mailbox for the user.
// ----------------------------------------------------------------------------
HRESULT CUserInfo::CreatePOP3Mailbox()
{
HRESULT hr = S_OK;
CComPtr<IP3Config> spConfig = NULL;
CComPtr<IAuthMethods> spMethods = NULL;
CComPtr<IAuthMethod> spAuth = NULL;
CComPtr<IP3Domains> spDomains = NULL;
CComPtr<IP3Domain> spDomain = NULL;
CComPtr<IP3Users> spUsers = NULL;
// Open our Pop3 Admin Interface
hr = CoCreateInstance(__uuidof(P3Config), NULL, CLSCTX_ALL, __uuidof(IP3Config), (LPVOID*)&spConfig);
if( SUCCEEDED(hr) )
{
// Get the Domains
hr = spConfig->get_Domains( &spDomains );
}
if( SUCCEEDED(hr) )
{
// Get the first domain
CComVariant cVar;
cVar = 1;
hr = spDomains->get_Item( cVar, &spDomain );
}
if( SUCCEEDED(hr) )
{
hr = spDomain->get_Users( &spUsers );
}
if ( SUCCEEDED(hr) )
{
hr = spConfig->get_Authentication( &spMethods );
}
CComVariant var;
if ( SUCCEEDED(hr) )
{
hr = spMethods->get_CurrentAuthMethod( &var );
}
if ( SUCCEEDED(hr) )
{
hr = spMethods->get_Item( var, &spAuth );
}
CComBSTR bstrID;
if( SUCCEEDED(hr) )
{
hr = spAuth->get_ID( &bstrID );
}
if( SUCCEEDED(hr) )
{
CComBSTR bstrName = (LPCTSTR)m_csEXAlias;
if( _tcsicmp(bstrID, SZ_AUTH_ID_MD5_HASH) == 0 )
{
CComBSTR bstrPassword = m_csPasswd;
hr = spUsers->AddEx( bstrName, bstrPassword );
SecureZeroMemory( (LPOLESTR)bstrPassword.m_str, sizeof(OLECHAR)*bstrPassword.Length() );
}
else
{
hr = spUsers->Add( bstrName );
}
}
return hr;
}
// ----------------------------------------------------------------------------
// SetPasswd()
// ----------------------------------------------------------------------------
HRESULT CUserInfo::SetPasswd()
{
HRESULT hr = S_OK;
TCHAR *szPath = NULL;
TCHAR *szTok = NULL;
CString csUser = _T("LDAP://");
if ( _tcsstr((LPCTSTR)m_csUserOU, _T("LDAP://")) )
{
csUser += m_csUserCN;
csUser += _T(",");
csUser += (LPCTSTR)m_csUserOU+7;
}
else
{
csUser += m_csUserCN;
csUser += _T(",");
csUser += (LPCTSTR)m_csUserOU;
}
// Now csUser is something like "WinNT://test.microsoft.com/JohnDoe,user"
CComPtr<IADsUser> spDS = NULL;
hr = ::ADsGetObject( (LPCWSTR)csUser, IID_IADsUser, (void**)&spDS );
if ( FAILED(hr) )
return(hr);
// Set the password.
if ( _tcslen((LPCTSTR)m_csPasswd) ) // Only if there IS a passwd!
{
CComBSTR bszPasswd = (LPCWSTR) m_csPasswd;
hr = spDS->SetPassword(bszPasswd);
if ( FAILED(hr) )
return(hr);
}
// Allow change?
if ( m_dwAccountOptions & PASSWD_NOCHANGE )
{
// Get the current ACL.
CComBSTR bstrName = csUser;
PACL pDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
hr = GetSDForDsObjectPath( bstrName, &pDACL, &pSD);
if( hr != S_OK ) return hr;
// build SID's for Self and World.
PSID pSidSelf = NULL;
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
if( !AllocateAndInitializeSid(&NtAuth, 1, SECURITY_PRINCIPAL_SELF_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSelf) )
{
return HRESULT_FROM_WIN32(GetLastError());
}
PSID pSidWorld;
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
if( !AllocateAndInitializeSid(&WorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidWorld) )
{
return HRESULT_FROM_WIN32(GetLastError());
}
// initialize the entries (DENY ACE's)
EXPLICIT_ACCESS rgAccessEntry[2] = {0};
OBJECTS_AND_SID rgObjectsAndSid[2] = {0};
rgAccessEntry[0].grfAccessPermissions = ACTRL_DS_CONTROL_ACCESS;
rgAccessEntry[0].grfAccessMode = DENY_ACCESS;
rgAccessEntry[0].grfInheritance = NO_INHERITANCE;
rgAccessEntry[1].grfAccessPermissions = ACTRL_DS_CONTROL_ACCESS;
rgAccessEntry[1].grfAccessMode = DENY_ACCESS;
rgAccessEntry[1].grfInheritance = NO_INHERITANCE;
// build the trustee structs for change password
GUID UserChangePasswordGUID = { 0xab721a53, 0x1e2f, 0x11d0, { 0x98, 0x19, 0x00, 0xaa, 0x00, 0x40, 0x52, 0x9b}};
BuildTrusteeWithObjectsAndSid( &(rgAccessEntry[0].Trustee), &(rgObjectsAndSid[0]), &UserChangePasswordGUID, NULL, pSidSelf );
BuildTrusteeWithObjectsAndSid( &(rgAccessEntry[1].Trustee), &(rgObjectsAndSid[1]), &UserChangePasswordGUID, NULL, pSidWorld );
// Build the new DACL
PACL pNewDACL = NULL;
DWORD dwErr = ::SetEntriesInAcl(2, rgAccessEntry, pDACL, &pNewDACL);
if( dwErr != ERROR_SUCCESS ) return HRESULT_FROM_WIN32(dwErr);
// Set the new DACL
hr = SetDaclForDsObjectPath( bstrName, pNewDACL );
if( hr != S_OK ) return hr;
LocalFree(pSD);
}
// SetInfo only if we actually changed anything.
if ( ( _tcslen((LPCTSTR)m_csPasswd) ) || // 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);
}
// ----------------------------------------------------------------------------
// JoinToGroup()
// ----------------------------------------------------------------------------
HRESULT CUserInfo::JoinToDomainUsers()
{
USES_CONVERSION;
HRESULT hr = S_OK;
CString csGroupName;
tstring strDomain;
tstring strUser;
// Get Domain SID
USER_MODALS_INFO_2 *pUserModalsInfo2;
NET_API_STATUS status = ::NetUserModalsGet( NULL, 2, (LPBYTE *)&pUserModalsInfo2 );
if ( (status != ERROR_SUCCESS) || (pUserModalsInfo2 == NULL) )
{
return E_FAIL;
}
PSID pSIDDomain = pUserModalsInfo2->usrmod2_domain_id;
// copy Domain RIDs
UCHAR nSubAuthorities = *::GetSidSubAuthorityCount(pSIDDomain);
DWORD adwSubAuthority[8];
for ( UCHAR index = 0; index < nSubAuthorities; index++ )
{
adwSubAuthority[index] = *::GetSidSubAuthority(pSIDDomain, index);
}
adwSubAuthority[nSubAuthorities++] = DOMAIN_GROUP_RID_USERS; // finally, append the RID we want.
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
PSID pSid = NULL;
if ( !::AllocateAndInitializeSid(&SIDAuthNT, nSubAuthorities,
adwSubAuthority[0], adwSubAuthority[1],
adwSubAuthority[2], adwSubAuthority[3],
adwSubAuthority[4], adwSubAuthority[5],
adwSubAuthority[6], adwSubAuthority[7],
&pSid) )
{
::NetApiBufferFree(pUserModalsInfo2);
return E_FAIL;
}
::NetApiBufferFree(pUserModalsInfo2);
// The builtin group names are looked up on the DC
TCHAR szDomain[MAX_PATH];
TCHAR szName[MAX_PATH];
DWORD cbDomain = MAX_PATH;
DWORD cbName = MAX_PATH;
SID_NAME_USE peUse;
if( !::LookupAccountSid( NULL, pSid, szName, &cbName, szDomain, &cbDomain, &peUse ) )
{
FreeSid(pSid);
return E_FAIL;
}
FreeSid( pSid );
// Find the Group Name
CString csTmp;
tstring strTmp = _T("LDAP://");
strTmp += m_csFQDomainName;
hr = FindADsObject(strTmp.c_str(), szName, _T("(name=%1)"), csTmp, 1, TRUE);
CHECK_HR( hr );
strTmp = _T("LDAP://");
strTmp += csTmp;
// Open the group
CComPtr<IADsGroup> spGroup = NULL;
hr = ::ADsGetObject( strTmp.c_str(), IID_IADsGroup, (void**)&spGroup );
if( SUCCEEDED(hr) )
{
// Add the User
CComBSTR bstrName = (LPCTSTR)m_csUserOU;
hr = spGroup->Add( bstrName );
if ( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS )
{
hr = S_FALSE;
}
}
return hr;
}