summaryrefslogtreecommitdiffstats
path: root/lib/isc/win32/ntgroups.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isc/win32/ntgroups.c')
-rw-r--r--lib/isc/win32/ntgroups.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/isc/win32/ntgroups.c b/lib/isc/win32/ntgroups.c
new file mode 100644
index 0000000..0584d48
--- /dev/null
+++ b/lib/isc/win32/ntgroups.c
@@ -0,0 +1,215 @@
+/*
+ * 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 <assert.h>
+#include <windows.h>
+#include <lm.h>
+/* clang-format on */
+
+#include <isc/ntgroups.h>
+#include <isc/result.h>
+
+#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);
+}