/* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, you can obtain one at https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ /* * The NT Groups have two groups that are not well documented and are * not normally seen: None and Everyone. A user account belongs to * any number of groups, but if it is not a member of any group then * it is a member of the None Group. The None group is not listed * anywhere. You cannot remove an account from the none group except * by making it a member of some other group, The second group is the * Everyone group. All accounts, no matter how many groups that they * belong to, also belong to the Everyone group. You cannot remove an * account from the Everyone group. */ #ifndef UNICODE #define UNICODE #endif /* UNICODE */ /* * Silence warnings. */ #define _CRT_SECURE_NO_DEPRECATE 1 /* clang-format off */ #include #include #include /* clang-format on */ #include #include #define MAX_NAME_LENGTH 256 #define CHECK(op) \ do { \ result = (op); \ if (result != ISC_R_SUCCESS) { \ goto cleanup; \ } \ } while (0) isc_result_t isc_ntsecurity_getaccountgroups(char *username, char **GroupList, unsigned int maxgroups, unsigned int *totalGroups) { LPGROUP_USERS_INFO_0 pTmpBuf; LPLOCALGROUP_USERS_INFO_0 pTmpLBuf; DWORD i; LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; LPGROUP_USERS_INFO_0 pgrpBuf = NULL; DWORD dwLevel = 0; DWORD dwFlags = LG_INCLUDE_INDIRECT; DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; NET_API_STATUS nStatus; size_t retlen; wchar_t user[MAX_NAME_LENGTH]; isc_result_t result; *totalGroups = 0; retlen = mbstowcs(user, username, MAX_NAME_LENGTH); if (retlen == (size_t)(-1)) { return (ISC_R_FAILURE); } /* * Call the NetUserGetLocalGroups function * specifying information level 0. * * The LG_INCLUDE_INDIRECT flag specifies that the * function should also return the names of the local * groups in which the user is indirectly a member. */ nStatus = NetUserGetLocalGroups(NULL, user, dwLevel, dwFlags, (LPBYTE *)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); /* * See if the call succeeds, */ if (nStatus != NERR_Success) { if (nStatus == ERROR_ACCESS_DENIED) { return (ISC_R_NOPERM); } if (nStatus == ERROR_MORE_DATA) { return (ISC_R_NOSPACE); } if (nStatus == NERR_UserNotFound) { dwEntriesRead = 0; } } if (pBuf != NULL) { pTmpLBuf = pBuf; /* * Loop through the entries */ for (i = 0; (i < dwEntriesRead && *totalGroups < maxgroups); i++) { assert(pTmpLBuf != NULL); if (pTmpLBuf == NULL) { break; } retlen = wcslen(pTmpLBuf->lgrui0_name); GroupList[*totalGroups] = (char *)malloc(retlen + 1); if (GroupList[*totalGroups] == NULL) { CHECK(ISC_R_NOMEMORY); } retlen = wcstombs(GroupList[*totalGroups], pTmpLBuf->lgrui0_name, retlen); if (retlen == (size_t)(-1)) { free(GroupList[*totalGroups]); CHECK(ISC_R_FAILURE); } GroupList[*totalGroups][retlen] = '\0'; if (strcmp(GroupList[*totalGroups], "None") == 0) { free(GroupList[*totalGroups]); } else { (*totalGroups)++; } pTmpLBuf++; } } /* Free the allocated memory. */ /* cppcheck-suppress duplicateCondition */ if (pBuf != NULL) { NetApiBufferFree(pBuf); } /* * Call the NetUserGetGroups function, specifying level 0. */ nStatus = NetUserGetGroups(NULL, user, dwLevel, (LPBYTE *)&pgrpBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); /* * See if the call succeeds, */ if (nStatus != NERR_Success) { if (nStatus == ERROR_ACCESS_DENIED) { return (ISC_R_NOPERM); } if (nStatus == ERROR_MORE_DATA) { return (ISC_R_NOSPACE); } if (nStatus == NERR_UserNotFound) { dwEntriesRead = 0; } } if (pgrpBuf != NULL) { pTmpBuf = pgrpBuf; /* * Loop through the entries */ for (i = 0; (i < dwEntriesRead && *totalGroups < maxgroups); i++) { assert(pTmpBuf != NULL); if (pTmpBuf == NULL) { break; } retlen = wcslen(pTmpBuf->grui0_name); GroupList[*totalGroups] = (char *)malloc(retlen + 1); if (GroupList[*totalGroups] == NULL) { CHECK(ISC_R_NOMEMORY); } retlen = wcstombs(GroupList[*totalGroups], pTmpBuf->grui0_name, retlen); if (retlen == (size_t)(-1)) { free(GroupList[*totalGroups]); CHECK(ISC_R_FAILURE); } GroupList[*totalGroups][retlen] = '\0'; if (strcmp(GroupList[*totalGroups], "None") == 0) { free(GroupList[*totalGroups]); } else { (*totalGroups)++; } pTmpBuf++; } } /* * Free the allocated memory. */ /* cppcheck-suppress duplicateCondition */ if (pgrpBuf != NULL) { NetApiBufferFree(pgrpBuf); } return (ISC_R_SUCCESS); cleanup: while (--(*totalGroups) > 0) { free(GroupList[*totalGroups]); } return (result); }