NTSTATUS NetOpenAlias( PNET_CONN pConn, PCWSTR pwszAliasname, DWORD dwAccessMask, ACCOUNT_HANDLE *phAlias, PDWORD pdwRid ) { const DWORD dwNumAliases = 1; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomains[2] = {0}; DOMAIN_HANDLE hDomain = NULL; ACCOUNT_HANDLE hAlias = NULL; PWSTR ppwszAliasnames[1] = {0}; PDWORD pdwRids = NULL; PDWORD pdwTypes = NULL; DWORD dwAliasRid = 0; DWORD i = 0; BAIL_ON_INVALID_PTR(pConn, err); BAIL_ON_INVALID_PTR(pwszAliasname, err); BAIL_ON_INVALID_PTR(phAlias, err); BAIL_ON_INVALID_PTR(pdwRid, err); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomains[0] = pConn->Rpc.Samr.hDomain; hDomains[1] = pConn->Rpc.Samr.hBuiltin; err = LwAllocateWc16String(&ppwszAliasnames[0], pwszAliasname); BAIL_ON_WIN_ERROR(err); /* * Try to look for alias in host domain first, then in builtin */ for (i = 0; i < sizeof(hDomains)/sizeof(hDomains[0]); i++) { status = SamrLookupNames(hSamrBinding, hDomains[i], dwNumAliases, ppwszAliasnames, (PUINT32*)&pdwRids, (PUINT32*)&pdwTypes, NULL); if (status == STATUS_SUCCESS) { /* * Alias has been found in one of domains so pass * that domain handle further down */ hDomain = hDomains[i]; dwAliasRid = pdwRids[0]; break; } else if (status == STATUS_NONE_MAPPED) { if (pdwRids) { SamrFreeMemory((void*)pdwRids); pdwRids = NULL; } if (pdwTypes) { SamrFreeMemory((void*)pdwTypes); pdwTypes = NULL; } continue; } /* Catch other possible errors */ BAIL_ON_NT_STATUS(status); } /* Allow to open alias only if a valid one has been found */ BAIL_ON_NT_STATUS(status); status = SamrOpenAlias(hSamrBinding, hDomain, dwAccessMask, dwAliasRid, &hAlias); BAIL_ON_NT_STATUS(status); *pdwRid = dwAliasRid; *phAlias = hAlias; cleanup: LW_SAFE_FREE_MEMORY(ppwszAliasnames[0]); if (pdwRids) { SamrFreeMemory((void*)pdwRids); } if (pdwTypes) { SamrFreeMemory((void*)pdwTypes); } return status; error: *pdwRid = 0; *phAlias = NULL; goto cleanup; }
NET_API_STATUS NetLocalGroupEnum( PCWSTR pwszHostname, DWORD dwLevel, PVOID *ppBuffer, DWORD dwMaxBufferSize, PDWORD pdwNumEntries, PDWORD pdwTotalNumEntries, PDWORD pdwResume ) { const DWORD dwAccountFlags = 0; const DWORD dwAliasAccessFlags = ALIAS_ACCESS_LOOKUP_INFO; const WORD wInfoLevel = ALIAS_INFO_ALL; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; DWORD dwResume = 0; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; DOMAIN_HANDLE hBtinDomain = NULL; DWORD dwSamrResume = 0; PWSTR *ppwszDomainAliases = NULL; PDWORD pdwDomainRids = NULL; DWORD dwNumDomainEntries = 0; DWORD dwTotalNumDomainEntries = 0; PWSTR *ppwszBtinDomainAliases = NULL; PDWORD pdwBtinDomainRids = NULL; DWORD dwNumBtinDomainEntries = 0; DWORD dwTotalNumBtinDomainEntries = 0; DWORD dwTotalNumEntries = 0; DWORD dwNumEntries = 0; DWORD i = 0; PDWORD pdwRids = NULL; PWSTR *ppwszAliases = NULL; ACCOUNT_HANDLE hAlias = NULL; AliasInfo *pSamrAliasInfo = NULL; AliasInfoAll **ppAliasInfo = NULL; DWORD dwInfoLevelSize = 0; PVOID pSourceBuffer = NULL; DWORD dwSize = 0; DWORD dwTotalSize = 0; DWORD dwSpaceAvailable = 0; PVOID pBuffer = NULL; PVOID pBufferCursor = NULL; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalNumEntries, err); BAIL_ON_INVALID_PTR(pdwResume, err); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_INFO_0); break; case 1: dwInfoLevelSize = sizeof(LOCALGROUP_INFO_1); break; default: err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } dwResume = *pdwResume; status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); status = NetConnectSamr(&pConn, pwszHostname, 0, 0, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; hBtinDomain = pConn->Rpc.Samr.hBuiltin; do { status = SamrEnumDomainAliases(hSamrBinding, hDomain, &dwSamrResume, dwAccountFlags, &ppwszDomainAliases, &pdwDomainRids, &dwNumDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); ppwszDomainAliases = NULL; } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); pdwDomainRids = NULL; } dwTotalNumDomainEntries += dwNumDomainEntries; dwNumDomainEntries = 0; } while (status == STATUS_MORE_ENTRIES); dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hBtinDomain, &dwSamrResume, dwAccountFlags, &ppwszBtinDomainAliases, &pdwBtinDomainRids, &dwNumBtinDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); ppwszBtinDomainAliases = NULL; } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); pdwBtinDomainRids = NULL; } dwTotalNumBtinDomainEntries += dwNumBtinDomainEntries; dwNumBtinDomainEntries = 0; } while (status == STATUS_MORE_ENTRIES); dwTotalNumEntries = dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries; status = NetAllocateMemory(OUT_PPVOID(&pdwRids), sizeof(pdwRids[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); status = NetAllocateMemory(OUT_PPVOID(&ppwszAliases), sizeof(ppwszAliases[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); status = NetAllocateMemory(OUT_PPVOID(&ppAliasInfo), sizeof(ppAliasInfo[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); dwTotalNumDomainEntries = 0; dwTotalNumBtinDomainEntries = 0; dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hDomain, &dwSamrResume, dwAccountFlags, &ppwszDomainAliases, &pdwDomainRids, &dwNumDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } for (i = 0; i < dwNumDomainEntries; i++) { err = LwAllocateWc16String(&ppwszAliases[dwTotalNumDomainEntries + i], ppwszDomainAliases[i]); BAIL_ON_WIN_ERROR(err); pdwRids[dwTotalNumDomainEntries + i] = pdwDomainRids[i]; } dwTotalNumDomainEntries += dwNumDomainEntries; dwNumDomainEntries = 0; if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); ppwszDomainAliases = NULL; } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); pdwDomainRids = NULL; } } while (status == STATUS_MORE_ENTRIES); dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hBtinDomain, &dwSamrResume, dwAccountFlags, &ppwszBtinDomainAliases, &pdwBtinDomainRids, &dwNumBtinDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } for (i = 0; i < dwNumBtinDomainEntries; i++) { err = LwAllocateWc16String(&ppwszAliases[dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries + i], ppwszBtinDomainAliases[i]); BAIL_ON_WIN_ERROR(err); pdwRids[dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries + i] = pdwBtinDomainRids[i]; } dwTotalNumBtinDomainEntries += dwNumBtinDomainEntries; dwNumBtinDomainEntries = 0; if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); ppwszBtinDomainAliases = NULL; } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); pdwBtinDomainRids = NULL; } } while (status == STATUS_MORE_ENTRIES); for (i = dwResume; i < dwTotalNumEntries; i++) { if (dwLevel == 0) { pSourceBuffer = ppwszAliases[i]; } else { DOMAIN_HANDLE hDom = NULL; DWORD dwRid = 0; hDom = (i < dwTotalNumDomainEntries) ? hDomain : hBtinDomain; dwRid = pdwRids[i]; status = SamrOpenAlias(hSamrBinding, hDom, dwAliasAccessFlags, dwRid, &hAlias); BAIL_ON_NT_STATUS(status); status = SamrQueryAliasInfo(hSamrBinding, hAlias, wInfoLevel, &pSamrAliasInfo); BAIL_ON_NT_STATUS(status); ppAliasInfo[i - dwResume] = &pSamrAliasInfo->all; pSourceBuffer = &pSamrAliasInfo->all; status = SamrClose(hSamrBinding, hAlias); BAIL_ON_NT_STATUS(status); } dwSize = 0; err = NetAllocateLocalGroupInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } if (dwTotalNumEntries > 0 && dwNumEntries == 0) { err = ERROR_INSUFFICIENT_BUFFER; BAIL_ON_WIN_ERROR(err); } if (dwTotalSize) { status = NetAllocateMemory(OUT_PPVOID(&pBuffer), dwTotalSize); BAIL_ON_NT_STATUS(status); } dwSize = 0; pBufferCursor = pBuffer; dwSpaceAvailable = dwTotalSize; for (i = 0; i < dwNumEntries; i++) { if (dwLevel == 0) { pSourceBuffer = ppwszAliases[dwResume + i]; } else { pSourceBuffer = ppAliasInfo[i]; } pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwResume + dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } *ppBuffer = pBuffer; *pdwNumEntries = dwNumEntries; *pdwTotalNumEntries = dwTotalNumEntries; *pdwResume = dwResume + dwNumEntries; cleanup: NetDisconnectSamr(&pConn); if (pdwRids) { NetFreeMemory(pdwRids); } if (ppwszAliases) { for (i = 0; i < dwTotalNumEntries; i++) { LW_SAFE_FREE_MEMORY(ppwszAliases[i]); } NetFreeMemory(ppwszAliases); } if (ppAliasInfo) { for (i = 0; i < dwNumEntries; i++) { if (ppAliasInfo[i]) { SamrFreeMemory(ppAliasInfo[i]); } } NetFreeMemory(ppAliasInfo); } if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); } if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); } if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = NtStatusToWin32Error(status); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; *pdwNumEntries = 0; *pdwTotalNumEntries = 0; *pdwResume = 0; goto cleanup; }
NTSTATUS NlAddGlobalGroupsToList( PLIST_ENTRY GroupList, ULONG LocalGroupID ) /*++ Routine Description: This procedure adds the global groups that are member of the given alias. Arguments: GroupList : List to munch. LocalGroupId : Rid of the local group. Return Value: Return NT Status code. --*/ { NTSTATUS Status; SAMPR_HANDLE AliasHandle = NULL; SAMPR_PSID_ARRAY Members = {0, NULL}; PULONG RidArray = NULL; DWORD RidArrayLength = 0; SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; DWORD i; // // Open Local Group // Status = SamrOpenAlias( NlGlobalChWorkerBuiltinDBHandle, 0, // No desired access LocalGroupID, &AliasHandle ); if (!NT_SUCCESS(Status)) { AliasHandle = NULL; goto Cleanup; } // // Enumerate members in this local group. // Status = SamrGetMembersInAlias( AliasHandle, &Members ); if (!NT_SUCCESS(Status)) { Members.Sids = NULL; goto Cleanup; } // // Determine the SIDs that belong to the Account Domain and get the // RIDs of them. // if( Members.Count == 0) { Status = STATUS_SUCCESS; goto Cleanup; } // // Allocate the maximum size RID array required. // RidArray = (PULONG)NetpMemoryAllocate( Members.Count * sizeof(ULONG) ); if( RidArray == NULL ) { Status = STATUS_NO_MEMORY; goto Cleanup; } for( i = 0; i < Members.Count; i++) { PUCHAR SubAuthorityCount; BOOLEAN EqualSid; SubAuthorityCount = RtlSubAuthorityCountSid(Members.Sids[i].SidPointer); (*SubAuthorityCount)--; EqualSid = RtlEqualSid( NlGlobalChWorkerSamDomainSid, Members.Sids[i].SidPointer ); (*SubAuthorityCount)++; if( EqualSid ) { RidArray[RidArrayLength] = *RtlSubAuthoritySid( Members.Sids[i].SidPointer, (*SubAuthorityCount) -1 ); RidArrayLength++; } } if( RidArrayLength == 0) { Status = STATUS_SUCCESS; goto Cleanup; } // // Get Group RIDs and add them to list. // Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle, RidArrayLength, RidArray, &Names, &Use ); if ( !NT_SUCCESS(Status) ) { Names.Element = NULL; Use.Element = NULL; if( Status == STATUS_NONE_MAPPED ) { // // if no SID is mapped, we can't do much here. // NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList could not map any SID from " "local group, RID = %lx \n", LocalGroupID )); Status = STATUS_SUCCESS; } goto Cleanup; } NlAssert( Names.Count == RidArrayLength ); NlAssert( Names.Element != NULL ); NlAssert( Use.Count == RidArrayLength ); NlAssert( Use.Element != NULL ); // // Find groups and add them to list. // for( i = 0; i < RidArrayLength; i++ ) { if( Use.Element[i] == SidTypeGroup ) { // // we found a group, add it to the list if it is not there // already. // if( NlGetGroupEntry( GroupList, RidArray[i] ) != NULL ) { // // entry already in the list. // continue; } // // add an entry to the list. // Status = NlAddGroupEntry( GroupList, RidArray[i] ); if ( !NT_SUCCESS(Status) ) { goto Cleanup; } } } Cleanup: if( Names.Element != NULL ) { SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names ); } if( Use.Element != NULL ) { SamIFree_SAMPR_ULONG_ARRAY( &Use ); } if( RidArray != NULL ) { NetpMemoryFree( RidArray ); } if ( Members.Sids != NULL ) { SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members ); } if( AliasHandle != NULL ) { SamrCloseHandle( &AliasHandle ); } if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList failed %lx\n", Status )); } return( Status ); }