ntgroups.c revision 290001
1/*
2 * Copyright (C) 2004, 2006, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: ntgroups.c,v 1.12 2009/09/29 23:48:04 tbox Exp $ */
19
20/*
21 * The NT Groups have two groups that are not well documented and are
22 * not normally seen: None and Everyone.  A user account belongs to
23 * any number of groups, but if it is not a member of any group then
24 * it is a member of the None Group. The None group is not listed
25 * anywhere. You cannot remove an account from the none group except
26 * by making it a member of some other group, The second group is the
27 * Everyone group.  All accounts, no matter how many groups that they
28 * belong to, also belong to the Everyone group. You cannot remove an
29 * account from the Everyone group.
30 */
31
32#ifndef UNICODE
33#define UNICODE
34#endif /* UNICODE */
35
36/*
37 * Silence warnings.
38 */
39#define _CRT_SECURE_NO_DEPRECATE 1
40
41#include <windows.h>
42#include <assert.h>
43#include <lm.h>
44
45#include <isc/ntgroups.h>
46#include <isc/result.h>
47
48#define MAX_NAME_LENGTH 256
49
50isc_result_t
51isc_ntsecurity_getaccountgroups(char *username, char **GroupList,
52				unsigned int maxgroups,
53				unsigned int *totalGroups) {
54	LPGROUP_USERS_INFO_0 pTmpBuf;
55	LPLOCALGROUP_USERS_INFO_0 pTmpLBuf;
56	DWORD i;
57	LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
58	LPGROUP_USERS_INFO_0 pgrpBuf = NULL;
59	DWORD dwLevel = 0;
60	DWORD dwFlags = LG_INCLUDE_INDIRECT;
61	DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
62	DWORD dwEntriesRead = 0;
63	DWORD dwTotalEntries = 0;
64	NET_API_STATUS nStatus;
65	DWORD dwTotalCount = 0;
66	size_t retlen;
67	wchar_t user[MAX_NAME_LENGTH];
68
69	retlen = mbstowcs(user, username, MAX_NAME_LENGTH);
70
71	*totalGroups = 0;
72	/*
73	 * Call the NetUserGetLocalGroups function
74	 * specifying information level 0.
75	 *
76	 * The LG_INCLUDE_INDIRECT flag specifies that the
77	 * function should also return the names of the local
78	 * groups in which the user is indirectly a member.
79	 */
80	nStatus = NetUserGetLocalGroups(NULL,
81				   user,
82				   dwLevel,
83				   dwFlags,
84				   (LPBYTE *) &pBuf,
85				   dwPrefMaxLen,
86				   &dwEntriesRead,
87				   &dwTotalEntries);
88	/*
89	 * See if the call succeeds,
90	 */
91	if (nStatus != NERR_Success) {
92		if (nStatus == ERROR_ACCESS_DENIED)
93			return (ISC_R_NOPERM);
94		if (nStatus == ERROR_MORE_DATA)
95			return (ISC_R_NOSPACE);
96		if (nStatus == NERR_UserNotFound)
97			dwEntriesRead = 0;
98	}
99
100	dwTotalCount = 0;
101	if (pBuf != NULL) {
102		pTmpLBuf = pBuf;
103		/*
104		 * Loop through the entries
105		 */
106		 for (i = 0;
107		     (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
108			assert(pTmpLBuf != NULL);
109			if (pTmpLBuf == NULL)
110				break;
111			retlen = wcslen(pTmpLBuf->lgrui0_name);
112			GroupList[*totalGroups] = (char *) malloc(retlen +1);
113			if (GroupList[*totalGroups] == NULL)
114				return (ISC_R_NOMEMORY);
115
116			retlen = wcstombs(GroupList[*totalGroups],
117				 pTmpLBuf->lgrui0_name, retlen);
118			GroupList[*totalGroups][retlen] = '\0';
119			if (strcmp(GroupList[*totalGroups], "None") == 0)
120				free(GroupList[*totalGroups]);
121			else
122				(*totalGroups)++;
123			pTmpLBuf++;
124		}
125	}
126	/* Free the allocated memory. */
127	if (pBuf != NULL)
128		NetApiBufferFree(pBuf);
129
130
131	/*
132	 * Call the NetUserGetGroups function, specifying level 0.
133	 */
134	nStatus = NetUserGetGroups(NULL,
135			      user,
136			      dwLevel,
137			      (LPBYTE*)&pgrpBuf,
138			      dwPrefMaxLen,
139			      &dwEntriesRead,
140			      &dwTotalEntries);
141	/*
142	 * See if the call succeeds,
143	 */
144	if (nStatus != NERR_Success) {
145		if (nStatus == ERROR_ACCESS_DENIED)
146			return (ISC_R_NOPERM);
147		if (nStatus == ERROR_MORE_DATA)
148			return (ISC_R_NOSPACE);
149		if (nStatus == NERR_UserNotFound)
150			dwEntriesRead = 0;
151	}
152
153	if (pgrpBuf != NULL) {
154		pTmpBuf = pgrpBuf;
155		/*
156		 * Loop through the entries
157		 */
158		 for (i = 0;
159		     (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
160			assert(pTmpBuf != NULL);
161
162			if (pTmpBuf == NULL)
163				break;
164			retlen = wcslen(pTmpBuf->grui0_name);
165			GroupList[*totalGroups] = (char *) malloc(retlen +1);
166			if (GroupList[*totalGroups] == NULL)
167				return (ISC_R_NOMEMORY);
168
169			retlen = wcstombs(GroupList[*totalGroups],
170				 pTmpBuf->grui0_name, retlen);
171			GroupList[*totalGroups][retlen] = '\0';
172			if (strcmp(GroupList[*totalGroups], "None") == 0)
173				free(GroupList[*totalGroups]);
174			else
175				(*totalGroups)++;
176			pTmpBuf++;
177		}
178	}
179	/*
180	 * Free the allocated memory.
181	 */
182	if (pgrpBuf != NULL)
183		NetApiBufferFree(pgrpBuf);
184
185	return (ISC_R_SUCCESS);
186}
187