/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * net_localgroupgetmembers.c * * Abstract: * * Remote Procedure Call (RPC) Client Interface * * NetLocalGroupGetMembers function * * Authors: Rafal Szczesniak (rafal@likewise.com) */ #include "includes.h" NET_API_STATUS NetLocalGroupGetMembers( IN PCWSTR pwszHostname, IN PCWSTR pwszAliasname, IN DWORD dwLevel, OUT PVOID *ppBuffer, IN DWORD dwMaxBufferSize, OUT PDWORD pdwNumEntries, OUT PDWORD pdwTotalEntries, OUT PDWORD pdwResume ) { const DWORD dwLsaAccessFlags = LSA_ACCESS_LOOKUP_NAMES_SIDS; const DWORD dwAliasAccessFlags = ALIAS_ACCESS_GET_MEMBERS; const WORD wLookupLevel = 1; NTSTATUS status = STATUS_SUCCESS; WINERR err = ERROR_SUCCESS; NetConn *pConn = NULL; handle_t hSamrBinding = NULL; handle_t hLsaBinding = NULL; DOMAIN_HANDLE hDomain = NULL; DOMAIN_HANDLE hBtinDomain = NULL; ACCOUNT_HANDLE hAlias = NULL; PSID *ppSids = NULL; DWORD dwInfoLevelSize = 0; DWORD dwTotalNumEntries = 0; DWORD dwResume = 0; DWORD dwAliasRid = 0; DWORD i = 0; DWORD dwNumSids = 0; DWORD dwCount = 0; POLICY_HANDLE hLsaPolicy = NULL; SidArray Sids = {0}; RefDomainList *pDomains = NULL; TranslatedName *pNames = NULL; PNET_RESOLVED_NAME pResolvedNames = 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; BAIL_ON_INVALID_PTR(pwszAliasname); BAIL_ON_INVALID_PTR(ppBuffer); BAIL_ON_INVALID_PTR(pdwNumEntries); BAIL_ON_INVALID_PTR(pdwTotalEntries); BAIL_ON_INVALID_PTR(pdwResume); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_MEMBERS_INFO_0); break; case 3: dwInfoLevelSize = sizeof(LOCALGROUP_MEMBERS_INFO_3); break; case 1: case 2: default: err = ERROR_INVALID_LEVEL; BAIL_ON_WINERR_ERROR(err); } dwResume = *pdwResume; status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NTSTATUS_ERROR(status); status = NetConnectSamr(&pConn, pwszHostname, 0, 0, pCreds); BAIL_ON_NTSTATUS_ERROR(status); hSamrBinding = pConn->samr.bind; hDomain = pConn->samr.hDomain; hBtinDomain = pConn->samr.hBtinDomain; status = NetOpenAlias(pConn, pwszAliasname, dwAliasAccessFlags, &hAlias, &dwAliasRid); if (status == STATUS_NONE_MAPPED) { /* No such alias in host's domain. Try to look in builtin domain. */ status = NetOpenAlias(pConn, pwszAliasname, dwAliasAccessFlags, &hAlias, &dwAliasRid); BAIL_ON_NTSTATUS_ERROR(status); } else if (status != STATUS_SUCCESS) { BAIL_ON_NTSTATUS_ERROR(status); } status = SamrGetMembersInAlias(hSamrBinding, hAlias, &ppSids, &dwNumSids); BAIL_ON_NTSTATUS_ERROR(status); status = SamrClose(hSamrBinding, hAlias); BAIL_ON_NTSTATUS_ERROR(status); dwTotalNumEntries = dwNumSids; if (dwLevel == 0) { for (i = 0; i + dwResume < dwNumSids; i++) { pSourceBuffer = ppSids[i + dwResume]; err = NetAllocateLocalGroupMembersInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize); BAIL_ON_WINERR_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } } else { status = NetConnectLsa(&pConn, pwszHostname, dwLsaAccessFlags, pCreds); BAIL_ON_NTSTATUS_ERROR(status); hLsaBinding = pConn->lsa.bind; hLsaPolicy = pConn->lsa.hPolicy; Sids.num_sids = dwNumSids; status = NetAllocateMemory((void**)&Sids.sids, sizeof(SidPtr) * Sids.num_sids, NULL); BAIL_ON_NTSTATUS_ERROR(status); for (i = 0; i < Sids.num_sids; i++) { Sids.sids[i].sid = ppSids[i]; } status = LsaLookupSids(hLsaBinding, hLsaPolicy, &Sids, &pDomains, &pNames, wLookupLevel, &dwCount); if (status != STATUS_SUCCESS && status != LW_STATUS_SOME_NOT_MAPPED) { BAIL_ON_NTSTATUS_ERROR(status); } status = NetAllocateMemory((void**)&pResolvedNames, sizeof(*pResolvedNames) * dwCount, NULL); BAIL_ON_NTSTATUS_ERROR(status); for (i = 0; i + dwResume < dwCount; i++) { DWORD iDomain = pNames[i + dwResume].sid_index; pResolvedNames[i].AccountName = pNames[i + dwResume].name; pResolvedNames[i].usType = pNames[i + dwResume].type; pResolvedNames[i].DomainName = pDomains->domains[iDomain].name; pSourceBuffer = pResolvedNames; err = NetAllocateLocalGroupMembersInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize); BAIL_ON_WINERR_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } } if (dwTotalNumEntries > 0 && dwNumEntries == 0) { err = ERROR_INSUFFICIENT_BUFFER; BAIL_ON_WINERR_ERROR(err); } if (dwTotalSize) { status = NetAllocateMemory((void**)&pBuffer, dwTotalSize, NULL); BAIL_ON_NTSTATUS_ERROR(status); } dwSize = 0; pBufferCursor = pBuffer; dwSpaceAvailable = dwTotalSize; for (i = 0; i < dwNumEntries; i++) { if (dwLevel == 0) { pSourceBuffer = ppSids[i + dwResume]; } else { pSourceBuffer = &(pResolvedNames[i]); } pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupMembersInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize); BAIL_ON_WINERR_ERROR(err); } if (dwResume + dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } *ppBuffer = pBuffer; *pdwResume = dwResume + dwNumEntries; *pdwNumEntries = dwNumEntries; *pdwTotalEntries = dwTotalNumEntries; cleanup: if (Sids.sids) { NetFreeMemory(Sids.sids); } if (ppSids) { SamrFreeMemory((void*)ppSids); } if (pNames) { SamrFreeMemory((void*)pNames); } if (pDomains) { SamrFreeMemory((void*)pDomains); } if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(status); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; goto cleanup; } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */