NET_API_STATUS NetUserGetLocalGroups( PCWSTR pwszHostname, PCWSTR pwszUsername, DWORD dwLevel, DWORD dwFlags, PVOID *ppBuffer, DWORD dwMaxBufferSize, PDWORD pdwNumEntries, PDWORD pdwTotalEntries ) { const DWORD dwBuiltinDomainAccess = DOMAIN_ACCESS_OPEN_ACCOUNT | DOMAIN_ACCESS_ENUM_ACCOUNTS; const DWORD dwUserAccess = USER_ACCESS_GET_GROUP_MEMBERSHIP; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; DOMAIN_HANDLE hBtinDomain = NULL; ACCOUNT_HANDLE hUser = NULL; PSID pDomainSid = NULL; PSID pUserSid = NULL; DWORD dwUserRid = 0; DWORD dwSidLen = 0; DWORD i = 0; PDWORD pdwUserRids = NULL; PDWORD pdwBuiltinUserRids = NULL; DWORD dwRidsCount = 0; DWORD dwBuiltinRidsCount = 0; DWORD dwInfoLevelSize = 0; DWORD dwTotalNumEntries = 0; PWSTR *ppwszAliasNames = NULL; PWSTR *ppwszBuiltinAliasNames = NULL; PDWORD pdwAliasTypes = NULL; PDWORD pdwBuiltinAliasTypes = NULL; PWSTR *ppwszLocalGroupNames = NULL; PVOID pSourceBuffer = NULL; PVOID pBuffer = NULL; PVOID pBufferCursor = NULL; DWORD dwSize = 0; DWORD dwTotalSize = 0; DWORD dwNumEntries = 0; DWORD dwSpaceAvailable = 0; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(pwszUsername, err); BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalEntries, err); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_USERS_INFO_0); break; default: err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); status = NetConnectSamr(&pConn, pwszHostname, 0, dwBuiltinDomainAccess, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; hBtinDomain = pConn->Rpc.Samr.hBuiltin; pDomainSid = pConn->Rpc.Samr.pDomainSid; status = NetOpenUser(pConn, pwszUsername, dwUserAccess, &hUser, &dwUserRid); BAIL_ON_NT_STATUS(status); dwSidLen = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1); err = LwAllocateMemory(dwSidLen, OUT_PPVOID(&pUserSid)); BAIL_ON_WIN_ERROR(err); status = RtlCopySid(dwSidLen, pUserSid, pDomainSid); BAIL_ON_NT_STATUS(status); status = RtlAppendRidSid(dwSidLen, pUserSid, dwUserRid); BAIL_ON_NT_STATUS(status); status = SamrGetAliasMembership(hSamrBinding, hDomain, &pUserSid, 1, &pdwUserRids, &dwRidsCount); BAIL_ON_NT_STATUS(status); status = SamrGetAliasMembership(hSamrBinding, hBtinDomain, &pUserSid, 1, &pdwBuiltinUserRids, &dwBuiltinRidsCount); BAIL_ON_NT_STATUS(status); dwTotalNumEntries = dwRidsCount + dwBuiltinRidsCount; err = LwAllocateMemory( sizeof(ppwszLocalGroupNames[0]) * dwTotalNumEntries, OUT_PPVOID(&ppwszLocalGroupNames)); BAIL_ON_WIN_ERROR(err); if (dwRidsCount > 0) { status = SamrLookupRids(hSamrBinding, hDomain, dwRidsCount, pdwUserRids, &ppwszAliasNames, &pdwAliasTypes); BAIL_ON_NT_STATUS(status); for (i = 0; i < dwRidsCount; i++) { ppwszLocalGroupNames[i] = ppwszAliasNames[i]; } } if (dwBuiltinRidsCount > 0) { status = SamrLookupRids(hSamrBinding, hBtinDomain, dwBuiltinRidsCount, pdwBuiltinUserRids, &ppwszBuiltinAliasNames, &pdwBuiltinAliasTypes); BAIL_ON_NT_STATUS(status); for (i = 0; i < dwBuiltinRidsCount; i++) { ppwszLocalGroupNames[i + dwRidsCount] = ppwszBuiltinAliasNames[i]; } } for (i = 0; i < dwTotalNumEntries; i++) { pSourceBuffer = ppwszLocalGroupNames[i]; dwSize = 0; err = NetAllocateLocalGroupUsersInfo(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++) { pSourceBuffer = ppwszLocalGroupNames[i]; pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupUsersInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } status = SamrClose(hSamrBinding, hUser); BAIL_ON_NT_STATUS(status); *ppBuffer = pBuffer; *pdwNumEntries = dwNumEntries; *pdwTotalEntries = dwTotalNumEntries; cleanup: LW_SAFE_FREE_MEMORY(pUserSid); LW_SAFE_FREE_MEMORY(ppwszLocalGroupNames); if (pdwUserRids) { SamrFreeMemory(pdwUserRids); } if (pdwBuiltinUserRids) { SamrFreeMemory(pdwBuiltinUserRids); } if (ppwszAliasNames) { SamrFreeMemory(ppwszAliasNames); } if (pdwAliasTypes) { SamrFreeMemory(pdwAliasTypes); } if (ppwszBuiltinAliasNames) { SamrFreeMemory(ppwszBuiltinAliasNames); } if (pdwBuiltinAliasTypes) { SamrFreeMemory(pdwBuiltinAliasTypes); } if (pCreds) { LwIoDeleteCreds(pCreds); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; *pdwNumEntries = 0; *pdwTotalEntries = 0; goto cleanup; }
static NTSTATUS LsaSrvLookupBuiltinSids( PPOLICY_CONTEXT pPolCtx, PACCOUNT_SIDS pAccountSids, RefDomainList *pDomains, TranslatedNameArray2 *pNamesArray, PDWORD pdwBuiltinDomainIndex ) { NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; DWORD dwBuiltinDomIndex = 0; LsaDomainInfo *pBuiltinDomainInfo = NULL; WCHAR wszBuiltinDomainName[] = LSA_BUILTIN_DOMAIN_NAME; PSID pBuiltinDomainSid = NULL; PDWORD pdwBuiltinRids = NULL; PWSTR *ppwszBuiltinNames = NULL; PDWORD pdwBuiltinTypes = NULL; DWORD i = 0; dwBuiltinDomIndex = pDomains->count; pBuiltinDomainInfo = &(pDomains->domains[dwBuiltinDomIndex]); dwError = LwAllocateWellKnownSid(WinBuiltinDomainSid, NULL, &pBuiltinDomainSid, NULL); BAIL_ON_LSA_ERROR(dwError); ntStatus = LsaSrvInitUnicodeStringEx(&pBuiltinDomainInfo->name, wszBuiltinDomainName); BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = LsaSrvDuplicateSid(&pBuiltinDomainInfo->sid, pBuiltinDomainSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); dwError = LwAllocateMemory( sizeof(pdwBuiltinRids[0]) * pAccountSids->dwCount, OUT_PPVOID(&pdwBuiltinRids)); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < pAccountSids->dwCount; i++) { PSID pSid = pAccountSids->ppSids[i]; DWORD iSubAuthority = pSid->SubAuthorityCount - 1; if (pSid->SubAuthorityCount == 2) { pdwBuiltinRids[i] = pSid->SubAuthority[iSubAuthority]; } else { /* This could be builtin domain SID to be resolved so just avoid accidental match with an existing RID */ pdwBuiltinRids[i] = 0; } } ntStatus = SamrLookupRids(pPolCtx->hSamrBinding, pPolCtx->hBuiltinDomain, pAccountSids->dwCount, pdwBuiltinRids, &ppwszBuiltinNames, &pdwBuiltinTypes); if (ntStatus != STATUS_SUCCESS && ntStatus != LW_STATUS_SOME_NOT_MAPPED && ntStatus != STATUS_NONE_MAPPED) { BAIL_ON_NTSTATUS_ERROR(ntStatus); } for (i = 0; i < pAccountSids->dwCount; i++) { DWORD iTransName = pAccountSids->pdwIndices[i]; TranslatedName2 *pDstBuiltinName = &(pNamesArray->names[iTransName]); if ((ntStatus == STATUS_SUCCESS || ntStatus == LW_STATUS_SOME_NOT_MAPPED) && ppwszBuiltinNames[i] != NULL) { /* RID (and thus SID) has been resolved to a name */ ntStatus = LsaSrvInitUnicodeString(&pDstBuiltinName->name, ppwszBuiltinNames[i]); BAIL_ON_NTSTATUS_ERROR(ntStatus); pDstBuiltinName->type = pdwBuiltinTypes[i]; pDstBuiltinName->sid_index = dwBuiltinDomIndex; } else if (pAccountSids->ppSids[i]->SubAuthorityCount == 1 && RtlIsPrefixSid(pAccountSids->ppSids[i], pBuiltinDomainInfo->sid)) { /* RID is unknown because SID turns out to be the builtin domain SID, not an account SID */ pDstBuiltinName->type = SID_TYPE_DOMAIN; pDstBuiltinName->sid_index = dwBuiltinDomIndex; } else { /* RID is unknown */ pDstBuiltinName->type = SID_TYPE_UNKNOWN; pDstBuiltinName->sid_index = 0; } pDstBuiltinName->unknown1 = 0; } pDomains->count = dwBuiltinDomIndex + 1; pNamesArray->count += pAccountSids->dwCount; *pdwBuiltinDomainIndex = dwBuiltinDomIndex; /* * Lookup status is checked later by the caller * so avoid bailing accidentally because other lookups * may be successful */ if (ntStatus == STATUS_SOME_NOT_MAPPED || ntStatus == STATUS_NONE_MAPPED) { ntStatus = STATUS_SUCCESS; } cleanup: LW_SAFE_FREE_MEMORY(pdwBuiltinRids); if (ppwszBuiltinNames) { SamrFreeMemory(ppwszBuiltinNames); } if (pdwBuiltinTypes) { SamrFreeMemory(pdwBuiltinTypes); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }