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.
759 lines
17 KiB
759 lines
17 KiB
#include "winnt.hxx"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
WINNT_GROUP WinNTGroup;
|
|
|
|
//
|
|
// This assumes that addr is an LPBYTE type.
|
|
//
|
|
#define WORD_ALIGN_DOWN(addr) \
|
|
addr = ((LPBYTE)((DWORD_PTR)addr & ~1))
|
|
|
|
DWORD WinNTGroupStrings[]=
|
|
|
|
{
|
|
FIELD_OFFSET(WINNT_GROUP, Parent),
|
|
FIELD_OFFSET(WINNT_GROUP, Computer),
|
|
FIELD_OFFSET(WINNT_GROUP, Domain),
|
|
FIELD_OFFSET(WINNT_GROUP, Name),
|
|
0xFFFFFFFF
|
|
};
|
|
|
|
|
|
BOOL
|
|
WinNTComputerOpen(
|
|
LPWSTR szDomainName,
|
|
LPWSTR szComputerName,
|
|
ULONG uGroupParent,
|
|
PHANDLE phComputer
|
|
)
|
|
{
|
|
WCHAR szTempBuffer[MAX_PATH];
|
|
PINICOMPUTER pIniComputer;
|
|
HRESULT hr;
|
|
|
|
|
|
if (!phComputer || (szComputerName == NULL) ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
pIniComputer = (PINICOMPUTER)AllocADsMem(
|
|
sizeof(INICOMPUTER)
|
|
);
|
|
if (!pIniComputer) {
|
|
return(FALSE);
|
|
}
|
|
|
|
hr = MakeUncName(
|
|
szComputerName,
|
|
szTempBuffer
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!(pIniComputer->szUncCompName = AllocADsStr(szTempBuffer))){
|
|
goto error;
|
|
}
|
|
|
|
if (szDomainName != NULL) {
|
|
if (!(pIniComputer->szDomainName = AllocADsStr(szDomainName))) {
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
if (!(pIniComputer->szComputerName = AllocADsStr(szComputerName))){
|
|
goto error;
|
|
}
|
|
|
|
pIniComputer->uGroupParent = uGroupParent;
|
|
|
|
*phComputer = (HANDLE)pIniComputer;
|
|
|
|
return(TRUE);
|
|
|
|
|
|
error:
|
|
if (pIniComputer) {
|
|
FreeIniComputer(pIniComputer);
|
|
}
|
|
|
|
*phComputer = NULL;
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WinNTEnumGlobalGroups(
|
|
HANDLE hComputer,
|
|
DWORD dwRequested,
|
|
LPBYTE * ppBuffer,
|
|
PDWORD pdwReturned
|
|
)
|
|
{
|
|
|
|
LPWINNT_GROUP * ppGroup = NULL;
|
|
DWORD i = 0;
|
|
BOOL dwRet = FALSE;
|
|
DWORD dwReturned = 0;
|
|
DWORD dwSize = 0;
|
|
LPWINNT_GROUP pBuffer = NULL;
|
|
LPBYTE pEnd = NULL;
|
|
BOOL retVal = FALSE;
|
|
|
|
ppGroup = (LPWINNT_GROUP *)AllocADsMem(
|
|
sizeof(LPWINNT_GROUP)* dwRequested
|
|
);
|
|
if (!ppGroup) {
|
|
return(FALSE);
|
|
}
|
|
|
|
for (i = 0; i < dwRequested; i++) {
|
|
|
|
dwRet = WinNTComputerGetGlobalGroup(
|
|
hComputer,
|
|
&ppGroup[i]
|
|
);
|
|
if (!dwRet) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
dwReturned = i;
|
|
|
|
dwRet = ComputeWinNTGroupDataSize(
|
|
ppGroup,
|
|
dwReturned,
|
|
&dwSize
|
|
);
|
|
|
|
pBuffer = (LPWINNT_GROUP)AllocADsMem(
|
|
dwSize
|
|
);
|
|
if (pBuffer) {
|
|
|
|
retVal = TRUE;
|
|
|
|
pEnd = (LPBYTE)((LPBYTE)(pBuffer) + dwSize);
|
|
|
|
for (i = 0; i < dwReturned; i++) {
|
|
|
|
pEnd = CopyIniWinNTGroupToWinNTGroup(
|
|
ppGroup[i],
|
|
(LPBYTE)(pBuffer + i),
|
|
pEnd
|
|
);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < dwReturned; i++ ) {
|
|
FreeIntWinNTGroup(*(ppGroup + i));
|
|
}
|
|
|
|
FreeADsMem(ppGroup);
|
|
|
|
//
|
|
// Will assign to NULL correctly if alloc failed.
|
|
//
|
|
*ppBuffer = (LPBYTE)pBuffer;
|
|
*pdwReturned = retVal ? dwReturned : 0;
|
|
|
|
if (!retVal) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if (dwReturned == dwRequested){
|
|
return(TRUE);
|
|
}else {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WinNTComputerGetGlobalGroup(
|
|
HANDLE hComputer,
|
|
LPWINNT_GROUP * ppGroup
|
|
)
|
|
{
|
|
BOOL dwRet = FALSE;
|
|
PINICOMPUTER pIniComp = (PINICOMPUTER)hComputer;
|
|
NET_API_STATUS nasStatus = 0;
|
|
GROUP_INFO_2 *pGroupInfo2 = NULL;
|
|
DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomainInfo = NULL;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((!pIniComp->_pBuffer) ||
|
|
(pIniComp->_dwCurrentObject == pIniComp->_dwObjectReturned)) {
|
|
|
|
if (pIniComp->_bNoMore) {
|
|
|
|
//
|
|
// No more objects to return
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pIniComp->_pBuffer) {
|
|
NetApiBufferFree(pIniComp->_pBuffer);
|
|
pIniComp->_pBuffer = NULL;
|
|
}
|
|
|
|
pIniComp->_dwObjectReturned = 0;
|
|
pIniComp->_dwCurrentObject = 0;
|
|
pIniComp->_dwTotalObjects = 0;
|
|
|
|
nasStatus = NetGroupEnum(
|
|
pIniComp->szUncCompName,
|
|
2,
|
|
&pIniComp->_pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&pIniComp->_dwObjectReturned,
|
|
&pIniComp->_dwTotalObjects,
|
|
&pIniComp->_dwResumeHandle
|
|
);
|
|
if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)){
|
|
SetLastError(nasStatus);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (nasStatus != ERROR_MORE_DATA) {
|
|
pIniComp->_bNoMore = TRUE;
|
|
}
|
|
|
|
pGroupInfo2 = (PGROUP_INFO_2) pIniComp->_pBuffer;
|
|
|
|
if ( (!pIniComp->_dwObjectReturned)) {
|
|
|
|
//
|
|
// We get success code (ERROR_SUCCESS) but the buffer was NULL:
|
|
// -> no global group was enumerated from the svr
|
|
//
|
|
|
|
return(FALSE);
|
|
|
|
} else if ( (1 == pIniComp->_dwTotalObjects) &&
|
|
(DOMAIN_GROUP_RID_USERS == pGroupInfo2->grpi2_group_id) ) {
|
|
// check if this is the none group. Only returned by non-DCs.
|
|
|
|
dwResult = DsRoleGetPrimaryDomainInformation(
|
|
pIniComp->szUncCompName,
|
|
DsRolePrimaryDomainInfoBasic, // InfoLevel
|
|
(PBYTE*)&pdomainInfo // pBuffer
|
|
);
|
|
hr = HRESULT_FROM_WIN32(dwResult);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(!( (pdomainInfo->MachineRole == DsRole_RoleBackupDomainController) ||
|
|
(pdomainInfo->MachineRole == DsRole_RolePrimaryDomainController) ) ) {
|
|
|
|
DsRoleFreeMemory(pdomainInfo);
|
|
(pIniComp->_dwCurrentObject)++;
|
|
return (FALSE);
|
|
}
|
|
else // it is a DC. Fall through.
|
|
;
|
|
}
|
|
}
|
|
|
|
dwRet = BuildWinNTGroupFromGlobalGroup(
|
|
hComputer,
|
|
(LPBYTE)((PGROUP_INFO_2) pIniComp->_pBuffer + pIniComp->_dwCurrentObject),
|
|
ppGroup
|
|
);
|
|
if (!dwRet) {
|
|
goto error;
|
|
}
|
|
|
|
pIniComp->_dwCurrentObject++;
|
|
|
|
if(pdomainInfo)
|
|
{
|
|
DsRoleFreeMemory(pdomainInfo);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
error:
|
|
|
|
if(pdomainInfo)
|
|
{
|
|
DsRoleFreeMemory(pdomainInfo);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL
|
|
WinNTEnumLocalGroups(
|
|
HANDLE hComputer,
|
|
DWORD dwRequested,
|
|
LPBYTE * ppBuffer,
|
|
PDWORD pdwReturned
|
|
)
|
|
{
|
|
|
|
LPWINNT_GROUP * ppGroup = NULL;
|
|
DWORD i = 0;
|
|
BOOL dwRet = FALSE;
|
|
DWORD dwReturned = 0;
|
|
DWORD dwSize = 0;
|
|
LPWINNT_GROUP pBuffer = NULL;
|
|
LPBYTE pEnd = NULL;
|
|
BOOL fretVal = FALSE;
|
|
|
|
|
|
ppGroup = (LPWINNT_GROUP *)AllocADsMem(
|
|
sizeof(LPWINNT_GROUP)* dwRequested
|
|
);
|
|
if (!ppGroup) {
|
|
return(FALSE);
|
|
}
|
|
|
|
for (i = 0; i < dwRequested; i++) {
|
|
|
|
dwRet = WinNTComputerGetLocalGroup(
|
|
hComputer,
|
|
&ppGroup[i]
|
|
);
|
|
if (!dwRet) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
dwReturned = i;
|
|
|
|
dwRet = ComputeWinNTGroupDataSize(
|
|
ppGroup,
|
|
dwReturned,
|
|
&dwSize
|
|
);
|
|
|
|
pBuffer = (LPWINNT_GROUP)AllocADsMem(
|
|
dwSize
|
|
);
|
|
|
|
if (pBuffer) {
|
|
|
|
fretVal = TRUE;
|
|
pEnd = (LPBYTE)((LPBYTE)(pBuffer) + dwSize);
|
|
|
|
for (i = 0; i < dwReturned; i++) {
|
|
|
|
pEnd = CopyIniWinNTGroupToWinNTGroup(
|
|
ppGroup[i],
|
|
(LPBYTE)(pBuffer + i),
|
|
pEnd
|
|
);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < dwReturned; i++ ) {
|
|
FreeIntWinNTGroup(*(ppGroup + i));
|
|
}
|
|
|
|
FreeADsMem(ppGroup);
|
|
|
|
//
|
|
// Will correctly assign to NULL if alloc failed.
|
|
//
|
|
*ppBuffer = (LPBYTE)pBuffer;
|
|
*pdwReturned = fretVal ? dwReturned : 0;
|
|
|
|
if (!fretVal) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if (dwReturned == dwRequested){
|
|
return(TRUE);
|
|
}else {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WinNTComputerGetLocalGroup(
|
|
HANDLE hComputer,
|
|
LPWINNT_GROUP * ppGroup
|
|
)
|
|
{
|
|
BOOL dwRet = FALSE;
|
|
PINICOMPUTER pIniComp = (PINICOMPUTER)hComputer;
|
|
NET_API_STATUS nasStatus = 0;
|
|
LPGROUP_INFO_0 pGroupInfo0 = NULL;
|
|
|
|
if ((!pIniComp->_pBuffer) ||
|
|
(pIniComp->_dwCurrentObject == pIniComp->_dwObjectReturned)) {
|
|
|
|
if (pIniComp->_bNoMore) {
|
|
|
|
//
|
|
// No more objects to return
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pIniComp->_pBuffer) {
|
|
NetApiBufferFree(pIniComp->_pBuffer);
|
|
pIniComp->_pBuffer = NULL;
|
|
}
|
|
|
|
pIniComp->_dwObjectReturned = 0;
|
|
pIniComp->_dwCurrentObject = 0;
|
|
pIniComp->_dwTotalObjects = 0;
|
|
|
|
nasStatus = NetLocalGroupEnum(
|
|
pIniComp->szUncCompName,
|
|
0,
|
|
&pIniComp->_pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&pIniComp->_dwObjectReturned,
|
|
&pIniComp->_dwTotalObjects,
|
|
&pIniComp->_dwResumeHandle
|
|
);
|
|
if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)){
|
|
SetLastError(nasStatus);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (nasStatus != ERROR_MORE_DATA) {
|
|
pIniComp->_bNoMore = TRUE;
|
|
}
|
|
|
|
|
|
pGroupInfo0 = (LPGROUP_INFO_0) pIniComp->_pBuffer;
|
|
|
|
if ( (!pIniComp->_dwObjectReturned)) {
|
|
|
|
//
|
|
// We get success code (ERROR_SUCCESS) but the buffer was NULL:
|
|
// -> no global group was enumerated from the svr
|
|
//
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// we will never get none group as a local group
|
|
|
|
}
|
|
|
|
dwRet = BuildWinNTGroupFromLocalGroup(
|
|
hComputer,
|
|
(LPBYTE)((LPLOCALGROUP_INFO_0)pIniComp->_pBuffer + pIniComp->_dwCurrentObject),
|
|
ppGroup
|
|
);
|
|
if (!dwRet) {
|
|
goto error;
|
|
}
|
|
|
|
pIniComp->_dwCurrentObject++;
|
|
|
|
return(TRUE);
|
|
|
|
error:
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
LPBYTE
|
|
CopyIniWinNTGroupToWinNTGroup(
|
|
LPWINNT_GROUP pIntGrp,
|
|
LPBYTE pExtGrp,
|
|
LPBYTE pEnd
|
|
)
|
|
{
|
|
LPWSTR SourceStrings[sizeof(WINNT_GROUP)/sizeof(LPWSTR)];
|
|
LPWSTR *pSourceStrings=SourceStrings;
|
|
LPWINNT_GROUP pWinNTGrp = (LPWINNT_GROUP)pExtGrp;
|
|
|
|
memset(SourceStrings, 0, sizeof(WINNT_GROUP));
|
|
*pSourceStrings++ = pIntGrp->Parent;
|
|
*pSourceStrings++ = pIntGrp->Computer;
|
|
*pSourceStrings++ = pIntGrp->Domain;
|
|
*pSourceStrings++ = pIntGrp->Name;
|
|
|
|
pEnd = PackStrings(
|
|
SourceStrings,
|
|
pExtGrp,
|
|
WinNTGroupStrings,
|
|
pEnd
|
|
);
|
|
|
|
pWinNTGrp->Type = pIntGrp->Type;
|
|
|
|
return pEnd;
|
|
}
|
|
|
|
BOOL
|
|
BuildWinNTGroupFromGlobalGroup(
|
|
HANDLE hComputer,
|
|
LPBYTE lpBuffer,
|
|
LPWINNT_GROUP * ppGroup
|
|
)
|
|
{
|
|
LPINICOMPUTER pComputer = (LPINICOMPUTER)hComputer;
|
|
LPWINNT_GROUP pGroup = NULL;
|
|
PGROUP_INFO_2 pGrp = (PGROUP_INFO_2)lpBuffer;
|
|
WCHAR szADsParent[MAX_PATH];
|
|
LPWSTR pMemberName = NULL;
|
|
DWORD cblen = 0;
|
|
|
|
pGroup = (LPWINNT_GROUP)AllocADsMem(
|
|
sizeof(WINNT_GROUP)
|
|
);
|
|
if (!pGroup) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Begin Global Group -> WinNT Group Mapping
|
|
//
|
|
|
|
pGroup->Name = AllocADsStr(pGrp->grpi2_name);
|
|
pGroup->Computer = AllocADsStr(pComputer->szComputerName);
|
|
pGroup->Domain = AllocADsStr(pComputer->szDomainName);
|
|
|
|
if (pComputer->uGroupParent == WINNT_DOMAIN_ID) {
|
|
wsprintf(
|
|
szADsParent,
|
|
L"%s://%s",
|
|
szProviderName,
|
|
pComputer->szDomainName
|
|
);
|
|
|
|
}else {
|
|
wsprintf(
|
|
szADsParent,
|
|
L"%s://%s/%s",
|
|
szProviderName,
|
|
pComputer->szDomainName,
|
|
pComputer->szComputerName
|
|
);
|
|
}
|
|
pGroup->Parent = AllocADsStr(szADsParent);
|
|
pGroup->Type = WINNT_GROUP_GLOBAL;
|
|
|
|
|
|
//
|
|
// End Global Group -> WinNT Group Mapping
|
|
//
|
|
|
|
*ppGroup = pGroup;
|
|
return(TRUE);
|
|
|
|
// error:
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
BuildWinNTGroupFromLocalGroup(
|
|
HANDLE hComputer,
|
|
LPBYTE lpBuffer,
|
|
LPWINNT_GROUP * ppGroup
|
|
)
|
|
{
|
|
LPINICOMPUTER pComputer = (LPINICOMPUTER)hComputer;
|
|
LPWINNT_GROUP pGroup = NULL;
|
|
LPLOCALGROUP_INFO_0 pGrp = (LPLOCALGROUP_INFO_0)lpBuffer;
|
|
WCHAR szADsParent[MAX_PATH];
|
|
LPWSTR pMemberName = NULL;
|
|
DWORD cblen = 0;
|
|
|
|
pGroup = (LPWINNT_GROUP)AllocADsMem(
|
|
sizeof(WINNT_GROUP)
|
|
);
|
|
if (!pGroup) {
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// Begin Local Group -> WinNT Group Mapping
|
|
//
|
|
|
|
pGroup->Name = AllocADsStr(pGrp->lgrpi0_name);
|
|
pGroup->Computer = AllocADsStr(pComputer->szComputerName);
|
|
pGroup->Domain = AllocADsStr(pComputer->szDomainName);
|
|
|
|
if (pComputer->uGroupParent == WINNT_DOMAIN_ID) {
|
|
wsprintf(
|
|
szADsParent,
|
|
L"%s://%s",
|
|
szProviderName,
|
|
pComputer->szDomainName
|
|
);
|
|
|
|
}else {
|
|
if (pComputer->szDomainName !=NULL) {
|
|
|
|
wsprintf(
|
|
szADsParent,
|
|
L"%s://%s/%s",
|
|
szProviderName,
|
|
pComputer->szDomainName,
|
|
pComputer->szComputerName
|
|
);
|
|
} else {
|
|
// This is a case where domain is null, the
|
|
// workstation service has not been started
|
|
wsprintf(
|
|
szADsParent,
|
|
L"%s://%s",
|
|
szProviderName,
|
|
pComputer->szComputerName
|
|
);
|
|
}
|
|
}
|
|
pGroup->Parent = AllocADsStr(szADsParent);
|
|
pGroup->Type = WINNT_GROUP_LOCAL;
|
|
|
|
|
|
//
|
|
// End Local Group -> WinNT Group Mapping
|
|
//
|
|
|
|
|
|
*ppGroup = pGroup;
|
|
return(TRUE);
|
|
|
|
|
|
// error:
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ComputeWinNTGroupDataSize(
|
|
LPWINNT_GROUP * ppGroups,
|
|
DWORD dwReturned,
|
|
PDWORD pdwSize
|
|
)
|
|
{
|
|
|
|
DWORD i = 0;
|
|
DWORD cb = 0;
|
|
LPWINNT_GROUP pGroup = NULL;
|
|
|
|
for (i = 0; i < dwReturned; i++) {
|
|
|
|
pGroup = *(ppGroups + i);
|
|
|
|
cb += sizeof(WINNT_GROUP);
|
|
|
|
if (pGroup->Parent) {
|
|
cb += wcslen(pGroup->Parent)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
}
|
|
|
|
if (pGroup->Computer) {
|
|
cb += wcslen(pGroup->Computer)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
}
|
|
|
|
if (pGroup->Domain) {
|
|
cb += wcslen(pGroup->Domain)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
}
|
|
|
|
if (pGroup->Name) {
|
|
cb += wcslen(pGroup->Name)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
*pdwSize = cb;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WinNTCloseComputer(
|
|
HANDLE hComputer
|
|
)
|
|
{
|
|
PINICOMPUTER pIniComputer = (PINICOMPUTER)hComputer;
|
|
|
|
if (pIniComputer) {
|
|
FreeIniComputer(pIniComputer);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
FreeIniComputer(
|
|
PINICOMPUTER pIniComputer
|
|
)
|
|
{
|
|
|
|
if (pIniComputer->szDomainName) {
|
|
|
|
FreeADsStr(pIniComputer->szDomainName);
|
|
}
|
|
|
|
if (pIniComputer->szComputerName) {
|
|
|
|
FreeADsStr(pIniComputer->szComputerName);
|
|
}
|
|
|
|
|
|
if (pIniComputer->szUncCompName) {
|
|
|
|
FreeADsStr(pIniComputer->szUncCompName);
|
|
}
|
|
|
|
|
|
if (pIniComputer->_pBuffer) {
|
|
NetApiBufferFree(pIniComputer->_pBuffer);
|
|
}
|
|
|
|
FreeADsMem(pIniComputer);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
FreeIntWinNTGroup(
|
|
LPWINNT_GROUP pGroup
|
|
)
|
|
{
|
|
if (pGroup->Parent) {
|
|
|
|
FreeADsStr(pGroup->Parent);
|
|
}
|
|
|
|
if (pGroup->Computer) {
|
|
|
|
FreeADsStr(pGroup->Computer);
|
|
}
|
|
|
|
|
|
if (pGroup->Domain) {
|
|
|
|
FreeADsStr(pGroup->Domain);
|
|
}
|
|
|
|
|
|
if (pGroup->Name) {
|
|
|
|
FreeADsStr(pGroup->Name);
|
|
}
|
|
|
|
|
|
if (pGroup) {
|
|
|
|
FreeADsMem(pGroup);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|