int main(void) { // GetCurrentProcess cannot fail HANDLE hProcess = GetCurrentProcess(); if (OpenProcessToken(hProcess, TOKEN_READ, &hProcess)) { LUID seCreateSymbolicLinkPrivilege; if (LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &seCreateSymbolicLinkPrivilege)) { DWORD length; printf("SeCreateSymbolicLinkPrivilege = %ld, %ld\n", seCreateSymbolicLinkPrivilege.HighPart, seCreateSymbolicLinkPrivilege.LowPart); if (!GetTokenInformation(hProcess, TokenPrivileges, NULL, 0, &length)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { TOKEN_PRIVILEGES* privileges = (TOKEN_PRIVILEGES*)malloc(length); if (GetTokenInformation(hProcess, TokenPrivileges, privileges, length, &length)) { BOOL found = FALSE; DWORD count = privileges->PrivilegeCount; printf("User has %ld privileges\n", count); if (count > 0) { LUID_AND_ATTRIBUTES* privs = privileges->Privileges; while (count-- > 0 && !luid_eq(privs->Luid, seCreateSymbolicLinkPrivilege)) privs++; found = (count > 0); } printf("User does%s have the SeCreateSymbolicLinkPrivilege\n", (found ? "" : "n't")); } else { fprintf(stderr, "Second GetTokenInformation failed\n"); } free(privileges); } else { fprintf(stderr, "First GetTokenInformation failed\n"); } } else { fprintf(stderr, "Impossible output from GetTokenInformation\n"); } } else { fprintf(stderr, "LookupPrivilegeValue failed\n"); } CloseHandle(hProcess); } else { fprintf(stderr, "OpenProcessToken failed\n"); } LSA_HANDLE hPolicy; NTSTATUS r; LSA_OBJECT_ATTRIBUTES attributes = {0, NULL, NULL, 0, NULL, NULL}; attributes.Length = sizeof(attributes); LUID seCreateSymbolicLinkPrivilege; if (LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &seCreateSymbolicLinkPrivilege)) { // POLICY_LOOKUP_NAMES: LsaLookupNames2, LsaEnumerateAccountRights, LsaLookupSids, LsaAddAccountRights // POLICY_VIEW_LOCAL_INFORMATION: LsaEnumerateAccountsWithUserRight // Elevation: LsaEnumerateAccountRights, LsaEnumerateAccountsWithUserRight, LsaRemoveAccountRights, LsaAddAccountRights if (NT_SUCCESS(r = LsaOpenPolicy(NULL, &attributes, POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, &hPolicy))) { LSA_REFERENCED_DOMAIN_LIST* referencedDomains; LSA_TRANSLATED_SID2* sids; LSA_UNICODE_STRING name; name.Buffer = L"Users"; name.Length = wcslen(name.Buffer) * sizeof(WCHAR); name.MaximumLength = name.Length + sizeof(WCHAR); if (NT_SUCCESS(r = LsaLookupNames2(hPolicy, LSA_LOOKUP_ISOLATED_AS_LOCAL, 1, &name, &referencedDomains, &sids))) { LSA_UNICODE_STRING* rights; ULONG count; LsaFreeMemory(referencedDomains); if (NT_SUCCESS(r = LsaEnumerateAccountRights(hPolicy, sids->Sid, &rights, &count))) { LSA_UNICODE_STRING* right = rights; printf("%ld right%s found\n", count, PLURAL(count)); while (count-- > 0) { printf(" %.*S\n", right->Length / 2, right->Buffer); right++; } LsaFreeMemory(rights); LSA_ENUMERATION_INFORMATION* allSidsRaw; LSA_UNICODE_STRING lsaCreateSymbolicLinkPrivilege; lsaCreateSymbolicLinkPrivilege.Buffer = SE_CREATE_SYMBOLIC_LINK_NAME; lsaCreateSymbolicLinkPrivilege.Length = wcslen(lsaCreateSymbolicLinkPrivilege.Buffer) * sizeof(WCHAR); lsaCreateSymbolicLinkPrivilege.MaximumLength = lsaCreateSymbolicLinkPrivilege.Length + sizeof(WCHAR); if (NT_SUCCESS(r = LsaEnumerateAccountsWithUserRight(hPolicy, &lsaCreateSymbolicLinkPrivilege, (void**)&allSidsRaw, &count))) { LSA_ENUMERATION_INFORMATION* sid = allSidsRaw; PSID* allSids; PSID* p; PLSA_TRANSLATED_NAME names; ULONG i = count; printf("%ld SID%s found\n", count, PLURAL(count)); p = allSids = (PSID*)malloc(count * sizeof(PSID)); while (i-- > 0) *p++ = (sid++)->Sid; if (NT_SUCCESS(r = LsaLookupSids(hPolicy, count, allSids, &referencedDomains, &names))) { PLSA_TRANSLATED_NAME name = names; BOOL usersAssigned = FALSE; LsaFreeMemory(referencedDomains); while (count-- > 0) { LPTSTR sidString; USHORT len = name->Name.Length / 2; ConvertSidToStringSid(*allSids++, &sidString); printf(" %.*S (%S)\n", len, name->Name.Buffer, sidString); usersAssigned |= (len > 4 && !wcsncmp(L"Users", name->Name.Buffer, len)); name++; LocalFree(sidString); } printf("Users had%s got SeCreateSymbolicLinkPrivilege\n", (usersAssigned ? "" : "n't")); if (usersAssigned) { if (!NT_SUCCESS(r = LsaRemoveAccountRights(hPolicy, sids->Sid, FALSE, &lsaCreateSymbolicLinkPrivilege, 1))) { fprintf(stderr, "Lsa failed with code %x\n", r); } } else { if (!NT_SUCCESS(r = LsaAddAccountRights(hPolicy, sids->Sid, &lsaCreateSymbolicLinkPrivilege, 1))) { fprintf(stderr, "LsaAddAccountRights failed with code %x\n", r); } } LsaFreeMemory(names); } else { fprintf(stderr, "LsaLookupSids2 failed with code %x\n", r); } LsaFreeMemory(allSidsRaw); free(allSids); } else { fprintf(stderr, "LsaEnumerateAccountsWithUserRight failed with code %x\n", r); } } else { fprintf(stderr, "LsaEnumerateAccountRights failed with code %x\n", r); } LsaFreeMemory(sids); } else { fprintf(stderr, "LsaLookupNames2 failed with code %x\n", r); } LsaClose(hPolicy); } else { fprintf(stderr, "LsaOpenPolicy failed with code %x\n", r); } } else { fprintf(stderr, "LookupPrivilegeValue failed\n"); } }
BOOL lsa_account_from_sid(LSA_HANDLE lsa_handle, PSID sid, PLSA_ACCOUNT account) { LSA_REFERENCED_DOMAIN_LIST* domain = 0; LSA_TRANSLATED_NAME* name = 0; NTSTATUS nt_status; BOOL success; if (sid == NULL) return print_error(L"Error in lsa_account_from_sid: sid is NULL.\n"); if (account == NULL) return print_error(L"Error in lsa_account_from_sid: account is NULL.\n"); nt_status = LsaLookupSids(lsa_handle, 1, &sid, &domain, &name); if (nt_status!=STATUS_SUCCESS) return lsa_error(nt_status, L"LsaLookupSids"); account->use = name->Use; if (name->DomainIndex >= 0 && name->DomainIndex < domain->Entries) success = copy_lsa_string_to_wchar(account->domain, sizeof(account->domain), &domain->Domains[name->DomainIndex].Name); else success = copy_lsa_string_to_wchar(account->domain, sizeof(account->domain), NULL); success &= copy_lsa_string_to_wchar(account->name, sizeof(account->name), &name->Name); LsaFreeMemory(domain); LsaFreeMemory(name); return success; }
static void test_LsaLookupSids(void) { LSA_REFERENCED_DOMAIN_LIST *list; LSA_OBJECT_ATTRIBUTES attrs; LSA_TRANSLATED_NAME *names; LSA_HANDLE policy; TOKEN_USER *user; NTSTATUS status; HANDLE token; DWORD size; BOOL ret; PSID sid; memset(&attrs, 0, sizeof(attrs)); attrs.Length = sizeof(attrs); status = LsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &policy); ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token); ok(ret, "got %d\n", ret); ret = GetTokenInformation(token, TokenUser, NULL, 0, &size); ok(!ret, "got %d\n", ret); user = HeapAlloc(GetProcessHeap(), 0, size); ret = GetTokenInformation(token, TokenUser, user, size, &size); ok(ret, "got %d\n", ret); status = LsaLookupSids(policy, 1, &user->User.Sid, &list, &names); ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); ok(list->Entries > 0, "got %d\n", list->Entries); if (list->Entries) { ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains); ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid); ok(list->Domains[0].Name.MaximumLength > list->Domains[0].Name.Length, "got %d, %d\n", list->Domains[0].Name.MaximumLength, list->Domains[0].Name.Length); } LsaFreeMemory(names); LsaFreeMemory(list); HeapFree(GetProcessHeap(), 0, user); CloseHandle(token); ret = ConvertStringSidToSidA("S-1-1-0", &sid); ok(ret == TRUE, "ConvertStringSidToSidA returned false\n"); status = LsaLookupSids(policy, 1, &sid, &list, &names); ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); ok(list->Entries > 0, "got %d\n", list->Entries); if (list->Entries) { ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains); ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid); ok(list->Domains[0].Name.MaximumLength > list->Domains[0].Name.Length, "got %d, %d\n", list->Domains[0].Name.MaximumLength, list->Domains[0].Name.Length); ok(list->Domains[0].Name.Buffer != NULL, "domain[0] name buffer is null\n"); } LsaFreeMemory(names); LsaFreeMemory(list); FreeSid(sid); status = LsaClose(policy); ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); }
static NTSTATUS LsaSrvLookupForeignDomainSids( PPOLICY_CONTEXT pPolCtx, PACCOUNT_SIDS pAccountSids, DWORD dwLevel, RefDomainList *pDomains, TranslatedNameArray2 *pNamesArray ) { NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PDOMAIN_ENTRY pDomEntry = NULL; handle_t hLsaBinding = NULL; POLICY_HANDLE hDcPolicy = NULL; PSID pDomSid = NULL; DWORD iDomSid = 0; DWORD iResolvSid = 0; DWORD iSid = 0; DWORD dwDomIndex = 0; ACCOUNT_SIDS ForeignSids = {0}; SID_ARRAY Sids = {0}; RefDomainList *pForeignDomains = NULL; TranslatedName *pForeignNames = NULL; DWORD dwForeignNamesCount = 0; DWORD iDomain = 0; DWORD i = 0; PSID pSid = NULL; DWORD dwSidIndex = 0; /* * Allocate enough space for potential sequence of sid lookups */ dwError = LwAllocateMemory( sizeof(ForeignSids.ppSids[0]) * pAccountSids->dwCount, OUT_PPVOID(&ForeignSids.ppSids)); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateMemory( sizeof(ForeignSids.pdwIndices[0]) * pAccountSids->dwCount, OUT_PPVOID(&ForeignSids.pdwIndices)); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateMemory( sizeof(Sids.pSids[0]) * pAccountSids->dwCount, OUT_PPVOID(&Sids.pSids)); BAIL_ON_LSA_ERROR(dwError); while (iDomSid < pAccountSids->dwCount) { ntStatus = RtlDuplicateSid(&pDomSid, pAccountSids->ppSids[iDomSid]); BAIL_ON_NTSTATUS_ERROR(ntStatus); pDomSid->SubAuthorityCount--; pDomSid->SubAuthority[pDomSid->SubAuthorityCount] = 0; iResolvSid = 0; for (iSid = iDomSid; iSid < pAccountSids->dwCount; iSid++) { pSid = pAccountSids->ppSids[iSid]; dwSidIndex = pAccountSids->pdwIndices[iSid]; if (RtlIsPrefixSid(pDomSid, pSid)) { ntStatus = RtlDuplicateSid( &(ForeignSids.ppSids[iResolvSid]), pSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); ForeignSids.pdwIndices[iResolvSid] = dwSidIndex; ForeignSids.dwCount = ++iResolvSid; /* * Free the sid so it's not looked up again */ RTL_FREE(&pAccountSids->ppSids[iSid]); pAccountSids->ppSids[iSid] = NULL; pSid = NULL; } } for (i = 0; i < ForeignSids.dwCount; i++) { Sids.pSids[i].pSid = ForeignSids.ppSids[i]; } Sids.dwNumSids = ForeignSids.dwCount; ntStatus = LsaSrvConnectDomainBySid(pPolCtx, pDomSid, &pDomEntry); BAIL_ON_NTSTATUS_ERROR(ntStatus); hLsaBinding = pDomEntry->hLsaBinding; hDcPolicy = pDomEntry->hPolicy; ntStatus = LsaLookupSids(hLsaBinding, hDcPolicy, &Sids, &pForeignDomains, &pForeignNames, dwLevel, &dwForeignNamesCount); if (ntStatus == STATUS_SUCCESS || ntStatus == STATUS_SOME_NOT_MAPPED) { for (iDomain = 0; iDomain < pForeignDomains->count; iDomain++) { LsaDomainInfo *pSrcDomInfo = NULL; LsaDomainInfo *pDstDomInfo = NULL; dwDomIndex = pDomains->count; pSrcDomInfo = &(pForeignDomains->domains[iDomain]); pDstDomInfo = &(pDomains->domains[dwDomIndex]); ntStatus = LsaSrvDuplicateUnicodeStringEx(&pDstDomInfo->name, &pSrcDomInfo->name); BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = LsaSrvDuplicateSid(&pDstDomInfo->sid, pSrcDomInfo->sid); BAIL_ON_NTSTATUS_ERROR(ntStatus); for (iSid = 0; iSid < dwForeignNamesCount; iSid++) { DWORD iTransName = ForeignSids.pdwIndices[iSid]; TranslatedName *pSrcName = &(pForeignNames[iSid]); TranslatedName2 *pDstName = &(pNamesArray->names[iTransName]); if (iDomain != pSrcName->sid_index) { continue; } ntStatus = LsaSrvDuplicateUnicodeString(&pDstName->name, &pSrcName->name); BAIL_ON_NTSTATUS_ERROR(ntStatus); pDstName->type = pSrcName->type; pDstName->sid_index = dwDomIndex; pDstName->unknown1 = 0; } pDomains->count = (++dwDomIndex); } pNamesArray->count += dwForeignNamesCount; } else if (ntStatus == STATUS_NONE_MAPPED) { for (i = 0; i < ForeignSids.dwCount; i++) { DWORD iTransName = ForeignSids.pdwIndices[i]; TranslatedName2 *pDstName = &(pNamesArray->names[iTransName]); pDstName->type = SID_TYPE_UNKNOWN; pDstName->sid_index = 0; pDstName->unknown1 = 0; } pNamesArray->count += ForeignSids.dwCount; } else { BAIL_ON_NTSTATUS_ERROR(ntStatus); } /* * Free the sids array before the next round of lookup. * The entire allocated space (i.e. as big as pAccountSids) * is cleaned up. */ for (i = 0; i < pAccountSids->dwCount; i++) { RTL_FREE(&(ForeignSids.ppSids[i])); ForeignSids.ppSids[i] = NULL; Sids.pSids[i].pSid = NULL; ForeignSids.pdwIndices[i] = -1; } Sids.dwNumSids = 0; if (pDomEntry) { LsaSrvDomainEntryFree(&pDomEntry); } if (pForeignDomains) { LsaRpcFreeMemory(pForeignDomains); pForeignDomains = NULL; } if (pForeignNames) { LsaRpcFreeMemory(pForeignNames); pForeignNames = NULL; } RTL_FREE(&pDomSid); /* * Find another domain name (first name that hasn't * been nulled out) */ iDomSid = 0; while (iDomSid < pAccountSids->dwCount && pAccountSids->ppSids[iDomSid] == NULL) { iDomSid++; } } /* * 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: for (i = 0; i < pAccountSids->dwCount; i++) { RTL_FREE(&(ForeignSids.ppSids[i])); } LW_SAFE_FREE_MEMORY(ForeignSids.ppSids); LW_SAFE_FREE_MEMORY(ForeignSids.pdwIndices); LW_SAFE_FREE_MEMORY(Sids.pSids); if (pDomEntry) { LsaSrvDomainEntryFree(&pDomEntry); } if (pForeignDomains) { LsaRpcFreeMemory(pForeignDomains); } if (pForeignNames) { LsaRpcFreeMemory(pForeignNames); } RTL_FREE(&pDomSid); if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }
static NTSTATUS LsaSrvLookupDomainSids( PPOLICY_CONTEXT pPolCtx, PACCOUNT_SIDS pAccountSids, DWORD dwLevel, RefDomainList *pDomains, TranslatedNameArray2 *pNamesArray ) { NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PDOMAIN_ENTRY pDomEntry = NULL; handle_t hLsaBinding = NULL; POLICY_HANDLE hDcPolicy = NULL; DWORD dwDomIndex = 0; SID_ARRAY Sids = {0}; RefDomainList *pDomain = NULL; TranslatedName *pDomainNames = NULL; DWORD dwDomainNamesCount = 0; DWORD iDomain = 0; DWORD iSid = 0; DWORD i = 0; ntStatus = LsaSrvGetDomainBySid(pPolCtx, pPolCtx->pDomainSid, &pDomEntry); if (ntStatus == STATUS_NO_SUCH_DOMAIN) { ntStatus = LsaSrvConnectDomainBySid(pPolCtx, pPolCtx->pDomainSid, &pDomEntry); BAIL_ON_NTSTATUS_ERROR(ntStatus); hLsaBinding = pDomEntry->hLsaBinding; hDcPolicy = pDomEntry->hPolicy; } else if (ntStatus == STATUS_SUCCESS) { hLsaBinding = pDomEntry->hLsaBinding; hDcPolicy = pDomEntry->hPolicy; } else { BAIL_ON_NTSTATUS_ERROR(ntStatus); } Sids.dwNumSids = pAccountSids->dwCount; dwError = LwAllocateMemory(sizeof(Sids.pSids[0]) * Sids.dwNumSids, OUT_PPVOID(&Sids.pSids)); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < Sids.dwNumSids; i++) { Sids.pSids[i].pSid = pAccountSids->ppSids[i]; } ntStatus = LsaLookupSids(hLsaBinding, hDcPolicy, &Sids, &pDomain, &pDomainNames, dwLevel, &dwDomainNamesCount); if (ntStatus == STATUS_SUCCESS || ntStatus == STATUS_SOME_NOT_MAPPED) { for (iDomain = 0; iDomain < pDomain->count; iDomain++) { LsaDomainInfo *pSrcDomInfo = NULL; LsaDomainInfo *pDstDomInfo = NULL; dwDomIndex = pDomains->count; pSrcDomInfo = &(pDomain->domains[iDomain]); pDstDomInfo = &(pDomains->domains[dwDomIndex]); ntStatus = LsaSrvDuplicateUnicodeStringEx(&pDstDomInfo->name, &pSrcDomInfo->name); BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = LsaSrvDuplicateSid(&pDstDomInfo->sid, pSrcDomInfo->sid); BAIL_ON_NTSTATUS_ERROR(ntStatus); for (iSid = 0; iSid < dwDomainNamesCount; iSid++) { DWORD iTransName = pAccountSids->pdwIndices[iSid]; TranslatedName *pSrcName = &(pDomainNames[iSid]); TranslatedName2 *pDstName = &(pNamesArray->names[iTransName]); if (iDomain != pSrcName->sid_index) { continue; } ntStatus = LsaSrvDuplicateUnicodeString(&pDstName->name, &pSrcName->name); BAIL_ON_NTSTATUS_ERROR(ntStatus); pDstName->type = pSrcName->type; pDstName->sid_index = dwDomIndex; pDstName->unknown1 = 0; } pDomains->count = (++dwDomIndex); } pNamesArray->count += dwDomainNamesCount; } else if (ntStatus == STATUS_NONE_MAPPED) { for (i = 0; i < pAccountSids->dwCount; i++) { DWORD iTransName = pAccountSids->pdwIndices[i]; TranslatedName2 *pDstName = &(pNamesArray->names[iTransName]); pDstName->type = SID_TYPE_UNKNOWN; pDstName->sid_index = 0; pDstName->unknown1 = 0; } pNamesArray->count += pAccountSids->dwCount; } else { BAIL_ON_NTSTATUS_ERROR(ntStatus); } /* * 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(Sids.pSids); if (pDomEntry) { LsaSrvDomainEntryFree(&pDomEntry); } if (pDomain) { LsaRpcFreeMemory(pDomain); } if (pDomainNames) { LsaRpcFreeMemory(pDomainNames); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }
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; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; LSA_BINDING hLsaBinding = 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; SID_ARRAY 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; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(pwszAliasname, err); BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalEntries, err); BAIL_ON_INVALID_PTR(pdwResume, err); 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_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; 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_NT_STATUS(status); } else if (status != STATUS_SUCCESS) { BAIL_ON_NT_STATUS(status); } status = SamrGetMembersInAlias(hSamrBinding, hAlias, &ppSids, &dwNumSids); BAIL_ON_NT_STATUS(status); status = SamrClose(hSamrBinding, hAlias); BAIL_ON_NT_STATUS(status); dwTotalNumEntries = dwNumSids; if (dwLevel == 0) { for (i = 0; i + dwResume < dwNumSids; i++) { pSourceBuffer = ppSids[i + dwResume]; err = NetAllocateLocalGroupMembersInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } } else { status = NetConnectLsa(&pConn, pwszHostname, dwLsaAccessFlags, pCreds); BAIL_ON_NT_STATUS(status); hLsaBinding = pConn->Rpc.Lsa.hBinding; hLsaPolicy = pConn->Rpc.Lsa.hPolicy; Sids.dwNumSids = dwNumSids; status = NetAllocateMemory(OUT_PPVOID(&Sids.pSids), sizeof(Sids.pSids[0]) * Sids.dwNumSids); BAIL_ON_NT_STATUS(status); for (i = 0; i < Sids.dwNumSids; i++) { Sids.pSids[i].pSid = ppSids[i]; } status = LsaLookupSids(hLsaBinding, hLsaPolicy, &Sids, &pDomains, &pNames, wLookupLevel, &dwCount); if (status != STATUS_SUCCESS && status != LW_STATUS_SOME_NOT_MAPPED) { BAIL_ON_NT_STATUS(status); } status = NetAllocateMemory(OUT_PPVOID(&pResolvedNames), sizeof(*pResolvedNames) * dwCount); BAIL_ON_NT_STATUS(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, 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 = ppSids[i + dwResume]; } else { pSourceBuffer = &(pResolvedNames[i]); } pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupMembersInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwResume + dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } *ppBuffer = pBuffer; *pdwResume = dwResume + dwNumEntries; *pdwNumEntries = dwNumEntries; *pdwTotalEntries = dwTotalNumEntries; cleanup: NetDisconnectSamr(&pConn); if (Sids.pSids) { NetFreeMemory(Sids.pSids); } if (ppSids) { SamrFreeMemory(ppSids); } if (pNames) { SamrFreeMemory(pNames); } if (pDomains) { SamrFreeMemory(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; }
static DWORD ProcessEnumerateAccounts( IN PRPC_PARAMETERS pRpcParams, IN PSTR UserRightName ) { DWORD err = ERROR_SUCCESS; NTSTATUS ntStatus = STATUS_SUCCESS; LSA_BINDING hLsa = NULL; LW_PIO_CREDS pCreds = NULL; WCHAR wszSysName[] = {'\\', '\\', '\0'}; DWORD policyAccessMask = LSA_ACCESS_LOOKUP_NAMES_SIDS | LSA_ACCESS_VIEW_POLICY_INFO; POLICY_HANDLE hPolicy = NULL; PWSTR pwszUserRightName = NULL; DWORD resume = 0; PSID *ppSids = NULL; DWORD numSids = 0; DWORD prefMaxSize = 64; DWORD i = 0; SID_ARRAY sids = {0}; RefDomainList *pDomList = NULL; TranslatedName *pTransNames = NULL; DWORD count = 0; PSTR pszAccountSid = NULL; PSTR pszAccountDomain = NULL; PSTR pszAccountName = NULL; BOOLEAN moreEntries = FALSE; err = CreateRpcCredentials(pRpcParams, &pCreds); BAIL_ON_LSA_ERROR(err); err = CreateLsaRpcBinding(pRpcParams, pCreds, &hLsa); BAIL_ON_LSA_ERROR(err); ntStatus = LsaOpenPolicy2(hLsa, wszSysName, NULL, policyAccessMask, &hPolicy); BAIL_ON_NT_STATUS(ntStatus); fprintf(stdout, "LSA Accounts"); do { moreEntries = FALSE; if (UserRightName) { fprintf(stdout, " with AccountRight = %s:\n", UserRightName); fprintf(stdout, "==================================================" "==============================\n"); err = LwMbsToWc16s(UserRightName, &pwszUserRightName); BAIL_ON_LSA_ERROR(err); ntStatus = LsaEnumAccountsWithUserRight( hLsa, hPolicy, pwszUserRightName, &ppSids, &numSids); BAIL_ON_NT_STATUS(ntStatus); } else { fprintf(stdout, ":\n"); fprintf(stdout, "==================================================" "==============================\n"); ntStatus = LsaEnumAccounts(hLsa, hPolicy, &resume, &ppSids, &numSids, prefMaxSize); if (ntStatus == STATUS_MORE_ENTRIES) { ntStatus = STATUS_SUCCESS; moreEntries = TRUE; } else if (ntStatus != STATUS_SUCCESS) { BAIL_ON_NT_STATUS(ntStatus); } } err = LwAllocateMemory( sizeof(sids.pSids[0]) * numSids, OUT_PPVOID(&sids.pSids)); BAIL_ON_LSA_ERROR(err); sids.dwNumSids = numSids; for (i = 0; i < sids.dwNumSids; i++) { sids.pSids[i].pSid = ppSids[i]; } ntStatus = LsaLookupSids(hLsa, hPolicy, &sids, &pDomList, &pTransNames, LSA_LOOKUP_NAMES_ALL, &count); if (ntStatus == STATUS_SOME_NOT_MAPPED || ntStatus == STATUS_NONE_MAPPED) { ntStatus = STATUS_SUCCESS; } else if (ntStatus != STATUS_SUCCESS) { BAIL_ON_NT_STATUS(ntStatus); } for (i = 0; i < sids.dwNumSids; i++) { DWORD domainIndex = 0; ntStatus = RtlAllocateCStringFromSid( &pszAccountSid, sids.pSids[i].pSid); BAIL_ON_NT_STATUS(ntStatus); if (pTransNames[i].type == SID_TYPE_USER || pTransNames[i].type == SID_TYPE_DOM_GRP || pTransNames[i].type == SID_TYPE_DOMAIN || pTransNames[i].type == SID_TYPE_ALIAS || pTransNames[i].type == SID_TYPE_WKN_GRP) { ntStatus = RtlCStringAllocateFromUnicodeString( &pszAccountName, &pTransNames[i].name); BAIL_ON_NT_STATUS(ntStatus); domainIndex = pTransNames[i].sid_index; ntStatus = RtlCStringAllocateFromUnicodeString( &pszAccountDomain, &pDomList->domains[domainIndex].name); BAIL_ON_NT_STATUS(ntStatus); } if (pszAccountSid) { fprintf(stdout, "%s ", pszAccountSid); } if (pszAccountDomain && pszAccountName) { fprintf(stdout, "(%s\\%s)", pszAccountDomain, pszAccountName); } else if (pszAccountDomain && !pszAccountName) { fprintf(stdout, "(%s\\)", pszAccountDomain); } else if (!pszAccountDomain && pszAccountName) { fprintf(stdout, "(%s)", pszAccountName); } else { fprintf(stdout, "(unknown)"); } fprintf(stdout, "\n"); RTL_FREE(&pszAccountSid); RTL_FREE(&pszAccountDomain); RTL_FREE(&pszAccountName); } if (pTransNames) { LsaRpcFreeMemory(pTransNames); pTransNames = NULL; } if (pDomList) { LsaRpcFreeMemory(pDomList); pDomList = NULL; } if (ppSids) { LsaRpcFreeMemory(ppSids); ppSids = NULL; } LW_SAFE_FREE_MEMORY(sids.pSids); } while (moreEntries && ntStatus == STATUS_SUCCESS); error: if (ntStatus || err) { PCSTR errName = LwNtStatusToName(ntStatus); PCSTR errDescription = LwNtStatusToDescription(ntStatus); if (ntStatus) { errName = LwNtStatusToName(ntStatus); errDescription = LwNtStatusToDescription(ntStatus); } else { errName = LwWin32ErrorToName(err); errDescription = LwWin32ErrorToDescription(err); } fprintf(stderr, "Error: %s (%s)\n", LSA_SAFE_LOG_STRING(errName), LSA_SAFE_LOG_STRING(errDescription)); } if (hPolicy) { LsaClose(hLsa, hPolicy); } if (hLsa) { LsaFreeBinding(&hLsa); } if (pCreds) { LwIoDeleteCreds(pCreds); } LW_SAFE_FREE_MEMORY(pwszUserRightName); RTL_FREE(&pszAccountSid); RTL_FREE(&pszAccountDomain); RTL_FREE(&pszAccountName); if (pTransNames) { LsaRpcFreeMemory(pTransNames); } if (pDomList) { LsaRpcFreeMemory(pDomList); } if (ppSids) { LsaRpcFreeMemory(ppSids); } LW_SAFE_FREE_MEMORY(sids.pSids); if (err == ERROR_SUCCESS && ntStatus != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(ntStatus); } return err; }