windows-nt/Source/XPSP1/NT/net/tapi/skywalker/rend/rnduser.cpp
2020-09-26 16:20:57 +08:00

699 lines
17 KiB
C++

/*++
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;
}