|
|
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
rnduser.cpp
Abstract:
This module contains implementation of CUser object.
Author:
Rajeevb,
Modification history:
Mu Han (muhan) 12-5-1997
--*/
#include "stdafx.h"
#include "rnduser.h"
const WCHAR * const UserAttributeNames[] = { L"SamAccountName", // ZoltanS: was "cn" -- we need SamAccountName for ntds.
L"telephoneNumber", L"IPPhone" };
#define INC_ACCESS_ACL_SIZE(_SIZE_, _SID_) \
_SIZE_ += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(_SID_));
#define BAIL_ON_BOOLFAIL(_FN_) \
if ( !_FN_ ) \ { \ hr = HRESULT_FROM_WIN32(GetLastError()); \ goto failed; \ }
#define ACCESS_READ 0x10
#define ACCESS_WRITE 0x20
#define ACCESS_MODIFY (ACCESS_WRITE | WRITE_DAC)
#define ACCESS_DELETE DELETE
#define ACCESS_ALL (ACCESS_READ | ACCESS_MODIFY | ACCESS_DELETE)
HRESULT ConvertStringToSid( IN PWSTR string, OUT PSID *sid, OUT PDWORD pdwSidSize, OUT PWSTR *end );
HRESULT ConvertACLToVariant( PACL pACL, LPVARIANT pvarACL );
/////////////////////////////////////////////////////////////////////////////
// non-interface class methods
/////////////////////////////////////////////////////////////////////////////
HRESULT CUser::Init(BSTR bName) { HRESULT hr;
hr = SetSingleValue(UA_USERNAME, bName); BAIL_IF_FAIL(hr, "can't set user name");
hr = SetDefaultSD(); BAIL_IF_FAIL(hr, "Init the security descriptor");
return hr; }
HRESULT CUser::GetSingleValueBstr( IN OBJECT_ATTRIBUTE Attribute, OUT BSTR * AttributeValue ) { LOG((MSP_INFO, "CUser::GetSingleValueBstr - entered"));
BAIL_IF_BAD_WRITE_PTR(AttributeValue, E_POINTER);
if (!ValidUserAttribute(Attribute)) { LOG((MSP_ERROR, "Invalid Attribute, %d", Attribute)); return E_FAIL; }
CLock Lock(m_lock); if(!m_Attributes[UserAttrIndex(Attribute)]) { LOG((MSP_ERROR, "Attribute %S is not found", UserAttributeName(Attribute))); return E_FAIL; }
*AttributeValue = SysAllocString(m_Attributes[UserAttrIndex(Attribute)]); if (*AttributeValue == NULL) { return E_OUTOFMEMORY; }
LOG((MSP_INFO, "CUser::get %S: %S", UserAttributeName(Attribute), *AttributeValue)); return S_OK; }
HRESULT CUser::SetSingleValue( IN OBJECT_ATTRIBUTE Attribute, IN WCHAR * AttributeValue ) { LOG((MSP_INFO, "CUser::SetSingleValue - entered"));
if (!ValidUserAttribute(Attribute)) { LOG((MSP_ERROR, "Invalid Attribute, %d", Attribute)); return E_FAIL; }
if (AttributeValue != NULL) { BAIL_IF_BAD_READ_PTR(AttributeValue, E_POINTER); }
CLock Lock(m_lock); if (!m_Attributes[UserAttrIndex(Attribute)].set(AttributeValue)) { LOG((MSP_ERROR, "Can not add attribute %S", UserAttributeName(Attribute))); return E_OUTOFMEMORY; }
LOG((MSP_INFO, "CUser::set %S to %S", UserAttributeName(Attribute), AttributeValue)); return S_OK; }
/*++
Routine Description: Set the right security descriptor for the conference. Arguments:
Return Value:
HRESULT.
--*/ HRESULT CUser::SetDefaultSD() { LOG((MSP_INFO, "CConference::SetDefaultSD - entered"));
//
// The security descriptor
//
IADsSecurityDescriptor* pSecDesc = NULL;
HRESULT hr = S_OK; bool bOwner = false, bWorld = false; PACL pACL = NULL; PSID pSidWorld = NULL; DWORD dwAclSize = sizeof(ACL), dwTemp; BSTR bstrTemp = NULL; LPWSTR pszTemp = NULL;
HANDLE hToken; UCHAR *pInfoBuffer = NULL; DWORD cbInfoBuffer = 512;
//
// Try to get the thread or process token
//
if( !OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken) ) { //
// If there was a sever error we exit
//
if( GetLastError() != ERROR_NO_TOKEN ) { LOG((MSP_ERROR, "CConference::SetDefaultSD - exit E_FAIL " "OpenThreadToken failed!")); return E_FAIL; }
//
// Attempt to open the process token, since no thread token exists
//
if( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ) { LOG((MSP_ERROR, "CConference::SetDefaultSD - exit E_FAIL " "OpenProcessToken failed")); return E_FAIL; } }
//
// Loop until we have a large enough structure
//
while ( (pInfoBuffer = new UCHAR[cbInfoBuffer]) != NULL ) { if ( !GetTokenInformation(hToken, TokenUser, pInfoBuffer, cbInfoBuffer, &cbInfoBuffer) ) { delete pInfoBuffer; pInfoBuffer = NULL;
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) return E_FAIL; } else { break; } }
CloseHandle(hToken);
//
// Did we get the owner ACL?
//
if ( pInfoBuffer ) { INC_ACCESS_ACL_SIZE( dwAclSize, ((PTOKEN_USER) pInfoBuffer)->User.Sid ); bOwner = true; }
//
// Make SID for "Everyone"
//
SysReAllocString( &bstrTemp, L"S-1-1-0" ); hr = ConvertStringToSid( bstrTemp, &pSidWorld, &dwTemp, &pszTemp ); if ( SUCCEEDED(hr) ) { INC_ACCESS_ACL_SIZE( dwAclSize, pSidWorld ); bWorld = true; }
//
// Create a security descriptor
//
hr = CoCreateInstance( CLSID_SecurityDescriptor, NULL, CLSCTX_INPROC_SERVER, IID_IADsSecurityDescriptor, (void **)&pSecDesc ); if( FAILED(hr) ) {
LOG((MSP_ERROR, "CConference::SetDefaultSD - exit 0x%08x " "Create security descriptor failed!", hr));
goto failed;
}
//
// Create the ACL containing the Owner and World ACEs
//
pACL = (PACL) new BYTE[dwAclSize]; if ( pACL ) { BAIL_ON_BOOLFAIL( InitializeAcl(pACL, dwAclSize, ACL_REVISION) );
// Add World Rights
if ( bWorld ) { if ( bOwner ) { BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_READ, pSidWorld) ); } else { BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_ALL , pSidWorld) ); } }
// Add Creator rights
if ( bOwner ) BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_ALL, ((PTOKEN_USER) pInfoBuffer)->User.Sid) );
// Set the DACL onto our security descriptor
VARIANT varDACL; VariantInit( &varDACL ); if ( SUCCEEDED(hr = ConvertACLToVariant((PACL) pACL, &varDACL)) ) { if ( SUCCEEDED(hr = pSecDesc->put_DaclDefaulted(FALSE)) ) { hr = pSecDesc->put_DiscretionaryAcl( V_DISPATCH(&varDACL) ); if( SUCCEEDED(hr) ) { hr = put_SecurityDescriptor((IDispatch*)pSecDesc); if( SUCCEEDED(hr) ) { hr = this->put_SecurityDescriptorIsModified(TRUE); } }
} } VariantClear( &varDACL ); } else { hr = E_OUTOFMEMORY; }
// Clean up
failed: SysFreeString( bstrTemp ); if ( pACL ) delete pACL; if ( pSidWorld ) delete pSidWorld; if ( pInfoBuffer ) delete pInfoBuffer; if( pSecDesc ) pSecDesc->Release();
LOG((MSP_INFO, "CConference::SetDefaultSD - exit 0x%08x", hr)); return hr; }
/////////////////////////////////////////////////////////////////////////////
// ITDirectoryObject
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CUser::get_Name(BSTR * ppVal) { return GetSingleValueBstr(UA_USERNAME, ppVal); }
STDMETHODIMP CUser::put_Name(BSTR pVal) { return SetSingleValue(UA_USERNAME, pVal); }
STDMETHODIMP CUser::get_DialableAddrs( IN long dwAddressTypes, //defined in tapi.h
OUT VARIANT * pVariant ) { BAIL_IF_BAD_WRITE_PTR(pVariant, E_POINTER); HRESULT hr;
BSTR *Addresses = new BSTR[1]; // only one for now.
BAIL_IF_NULL(Addresses, E_OUTOFMEMORY);
switch (dwAddressTypes) { case LINEADDRESSTYPE_DOMAINNAME: hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &Addresses[0]); break;
case LINEADDRESSTYPE_IPADDRESS: { BSTR pDomainName; DWORD dwIP;
hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &pDomainName);
if ( SUCCEEDED(hr) ) { hr = ResolveHostName(0, pDomainName, NULL, &dwIP);
SysFreeString(pDomainName);
if ( SUCCEEDED(hr) ) { WCHAR wszIP[20];
ipAddressToStringW(wszIP, dwIP);
Addresses[0] = SysAllocString(wszIP);
if ( Addresses[0] == NULL ) { hr = E_OUTOFMEMORY; } } } } break; case LINEADDRESSTYPE_PHONENUMBER: hr = GetSingleValueBstr(UA_TELEPHONE_NUMBER, &Addresses[0]); break;
default: hr = E_FAIL; break; }
DWORD dwCount = (FAILED(hr)) ? 0 : 1; hr = ::CreateBstrCollection(dwCount, // count
&Addresses[0], // begin pointer
&Addresses[dwCount], // end pointer
pVariant, // return value
AtlFlagTakeOwnership); // flags
// the collection will destroy the Addresses array eventually.
// no need to free anything here. Even if we tell it to hand
// out zero objects, it will delete the array on construction.
// (ZoltanS verified.)
return hr; }
STDMETHODIMP CUser::EnumerateDialableAddrs( IN DWORD dwAddressTypes, //defined in tapi.h
OUT IEnumDialableAddrs ** ppEnumDialableAddrs ) { BAIL_IF_BAD_WRITE_PTR(ppEnumDialableAddrs, E_POINTER);
HRESULT hr;
BSTR *Addresses = new BSTR[1]; // only one for now.
BAIL_IF_NULL(Addresses, E_OUTOFMEMORY);
switch (dwAddressTypes) { case LINEADDRESSTYPE_IPADDRESS: { BSTR pDomainName; DWORD dwIP;
hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &pDomainName);
if ( SUCCEEDED(hr) ) { hr = ResolveHostName(0, pDomainName, NULL, &dwIP);
SysFreeString(pDomainName);
if ( SUCCEEDED(hr) ) { WCHAR wszIP[20];
ipAddressToStringW(wszIP, dwIP);
Addresses[0] = SysAllocString(wszIP);
if ( Addresses[0] == NULL ) { hr = E_OUTOFMEMORY; } } } } break;
case LINEADDRESSTYPE_DOMAINNAME: hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &Addresses[0]); break; case LINEADDRESSTYPE_PHONENUMBER: hr = GetSingleValueBstr(UA_TELEPHONE_NUMBER, &Addresses[0]); break;
default: hr = E_FAIL; break; }
DWORD dwCount = (FAILED(hr)) ? 0 : 1; hr = ::CreateDialableAddressEnumerator( &Addresses[0], &Addresses[dwCount], ppEnumDialableAddrs ); // the enumerator will destroy the Addresses array eventually,
// so no need to free anything here. Even if we tell it to hand
// out zero objects, it will delete the array on destruction.
// (ZoltanS verified.)
return hr; }
STDMETHODIMP CUser::GetAttribute( IN OBJECT_ATTRIBUTE Attribute, OUT BSTR * ppAttributeValue ) { return GetSingleValueBstr(Attribute, ppAttributeValue); }
STDMETHODIMP CUser::SetAttribute( IN OBJECT_ATTRIBUTE Attribute, IN BSTR pAttributeValue ) { return SetSingleValue(Attribute, pAttributeValue); }
STDMETHODIMP CUser::GetTTL( OUT DWORD * pdwTTL ) { BAIL_IF_BAD_WRITE_PTR(pdwTTL, E_POINTER);
*pdwTTL = 0;
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// ITDirectoryObjectUser
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CUser::get_IPPhonePrimary( OUT BSTR *pVal ) { return GetSingleValueBstr(UA_IPPHONE_PRIMARY, pVal); }
STDMETHODIMP CUser::put_IPPhonePrimary( IN BSTR newVal ) { // ZoltanS: we now need to check the BSTR, as the ResolveHostName
// call below doesn't check it before using it.
// Second argument is the maximum length of string to check -- we want
// to check the whole thing, so we say (UINT) -1, which is about 2^32.
if ( IsBadStringPtr(newVal, (UINT) -1) ) { LOG((MSP_ERROR, "CUser::put_IPPhonePrimary: bad BSTR")); return E_POINTER; } // ZoltanS: We shouldn't let the user set an IPPhonePrimary value that
// doesn't resolve to a known host / IP. Check here.
char * pchFullDNSName = NULL; // we don't really care what we get
DWORD dwIp = 0; // we don't really care what we get
// This is our utility function from rndutil.cpp.
HRESULT hr = ResolveHostName(0, newVal, &pchFullDNSName, &dwIp); if (FAILED(hr)) { LOG((MSP_ERROR, "CUser::put_IPPhonePrimary: unresolvable name")); return hr; } // Now actually set it.
return SetSingleValue(UA_IPPHONE_PRIMARY, newVal); }
typedef IDispatchImpl<ITDirectoryObjectUserVtbl<CUser>, &IID_ITDirectoryObjectUser, &LIBID_RENDLib> CTDirObjUser;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
//
// CUser::GetIDsOfNames
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
STDMETHODIMP CUser::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid ) { LOG((MSP_TRACE, "CUser::GetIDsOfNames[%p] - enter. Name [%S]",this, *rgszNames));
HRESULT hr = DISP_E_UNKNOWNNAME;
//
// See if the requsted method belongs to the default interface
//
hr = CTDirObjUser::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); if (SUCCEEDED(hr)) { LOG((MSP_TRACE, "CUser::GetIDsOfNames - found %S on CTDirObjUser", *rgszNames)); rgdispid[0] |= IDISPDIROBJUSER; return hr; }
//
// If not, then try the CDirectoryObject base class
//
hr = CDirectoryObject::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); if (SUCCEEDED(hr)) { LOG((MSP_TRACE, "CUser::GetIDsOfNames - found %S on CDirectoryObject", *rgszNames)); rgdispid[0] |= IDISPDIROBJECT; return hr; }
LOG((MSP_ERROR, "CUser::GetIDsOfNames[%p] - finish. didn't find %S on our iterfaces",*rgszNames));
return hr; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
//
// CUser::Invoke
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
STDMETHODIMP CUser::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr ) { LOG((MSP_TRACE, "CUser::Invoke[%p] - enter. dispidMember %lx",this, dispidMember));
HRESULT hr = DISP_E_MEMBERNOTFOUND; DWORD dwInterface = (dispidMember & INTERFACEMASK); //
// Call invoke for the required interface
//
switch (dwInterface) { case IDISPDIROBJUSER: { hr = CTDirObjUser::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr ); LOG((MSP_TRACE, "CUser::Invoke - ITDirectoryObjectUser"));
break; }
case IDISPDIROBJECT: { hr = CDirectoryObject::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr );
LOG((MSP_TRACE, "CUser::Invoke - ITDirectoryObject"));
break; }
} // end switch (dwInterface)
LOG((MSP_TRACE, "CUser::Invoke[%p] - finish. hr = %lx", hr));
return hr; }
|