1258945Sroberto/*
2280849Scy * Copyright (C) 2004, 2006, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 2001  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id: ntgroups.c,v 1.12 2009/09/29 23:48:04 tbox Exp $ */
19258945Sroberto
20258945Sroberto/*
21258945Sroberto * The NT Groups have two groups that are not well documented and are
22258945Sroberto * not normally seen: None and Everyone.  A user account belongs to
23258945Sroberto * any number of groups, but if it is not a member of any group then
24258945Sroberto * it is a member of the None Group. The None group is not listed
25258945Sroberto * anywhere. You cannot remove an account from the none group except
26258945Sroberto * by making it a member of some other group, The second group is the
27258945Sroberto * Everyone group.  All accounts, no matter how many groups that they
28258945Sroberto * belong to, also belong to the Everyone group. You cannot remove an
29258945Sroberto * account from the Everyone group.
30258945Sroberto */
31258945Sroberto
32258945Sroberto#ifndef UNICODE
33258945Sroberto#define UNICODE
34258945Sroberto#endif /* UNICODE */
35258945Sroberto
36258945Sroberto/*
37258945Sroberto * Silence warnings.
38258945Sroberto */
39258945Sroberto#define _CRT_SECURE_NO_DEPRECATE 1
40258945Sroberto
41258945Sroberto#include <windows.h>
42258945Sroberto#include <assert.h>
43258945Sroberto#include <lm.h>
44258945Sroberto
45258945Sroberto#include <isc/ntgroups.h>
46258945Sroberto#include <isc/result.h>
47258945Sroberto
48258945Sroberto#define MAX_NAME_LENGTH 256
49258945Sroberto
50258945Srobertoisc_result_t
51258945Srobertoisc_ntsecurity_getaccountgroups(char *username, char **GroupList,
52258945Sroberto				unsigned int maxgroups,
53258945Sroberto				unsigned int *totalGroups) {
54258945Sroberto	LPGROUP_USERS_INFO_0 pTmpBuf;
55258945Sroberto	LPLOCALGROUP_USERS_INFO_0 pTmpLBuf;
56258945Sroberto	DWORD i;
57258945Sroberto	LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
58258945Sroberto	LPGROUP_USERS_INFO_0 pgrpBuf = NULL;
59258945Sroberto	DWORD dwLevel = 0;
60258945Sroberto	DWORD dwFlags = LG_INCLUDE_INDIRECT;
61258945Sroberto	DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
62258945Sroberto	DWORD dwEntriesRead = 0;
63258945Sroberto	DWORD dwTotalEntries = 0;
64258945Sroberto	NET_API_STATUS nStatus;
65258945Sroberto	DWORD dwTotalCount = 0;
66280849Scy	size_t retlen;
67258945Sroberto	wchar_t user[MAX_NAME_LENGTH];
68258945Sroberto
69258945Sroberto	retlen = mbstowcs(user, username, MAX_NAME_LENGTH);
70258945Sroberto
71258945Sroberto	*totalGroups = 0;
72258945Sroberto	/*
73280849Scy	 * Call the NetUserGetLocalGroups function
74258945Sroberto	 * specifying information level 0.
75258945Sroberto	 *
76280849Scy	 * The LG_INCLUDE_INDIRECT flag specifies that the
77280849Scy	 * function should also return the names of the local
78258945Sroberto	 * groups in which the user is indirectly a member.
79258945Sroberto	 */
80258945Sroberto	nStatus = NetUserGetLocalGroups(NULL,
81280849Scy				   user,
82280849Scy				   dwLevel,
83280849Scy				   dwFlags,
84280849Scy				   (LPBYTE *) &pBuf,
85280849Scy				   dwPrefMaxLen,
86280849Scy				   &dwEntriesRead,
87280849Scy				   &dwTotalEntries);
88258945Sroberto	/*
89258945Sroberto	 * See if the call succeeds,
90258945Sroberto	 */
91258945Sroberto	if (nStatus != NERR_Success) {
92258945Sroberto		if (nStatus == ERROR_ACCESS_DENIED)
93258945Sroberto			return (ISC_R_NOPERM);
94258945Sroberto		if (nStatus == ERROR_MORE_DATA)
95258945Sroberto			return (ISC_R_NOSPACE);
96258945Sroberto		if (nStatus == NERR_UserNotFound)
97258945Sroberto			dwEntriesRead = 0;
98258945Sroberto	}
99258945Sroberto
100258945Sroberto	dwTotalCount = 0;
101258945Sroberto	if (pBuf != NULL) {
102258945Sroberto		pTmpLBuf = pBuf;
103258945Sroberto		/*
104258945Sroberto		 * Loop through the entries
105258945Sroberto		 */
106280849Scy		 for (i = 0;
107258945Sroberto		     (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
108258945Sroberto			assert(pTmpLBuf != NULL);
109258945Sroberto			if (pTmpLBuf == NULL)
110258945Sroberto				break;
111258945Sroberto			retlen = wcslen(pTmpLBuf->lgrui0_name);
112258945Sroberto			GroupList[*totalGroups] = (char *) malloc(retlen +1);
113258945Sroberto			if (GroupList[*totalGroups] == NULL)
114258945Sroberto				return (ISC_R_NOMEMORY);
115258945Sroberto
116258945Sroberto			retlen = wcstombs(GroupList[*totalGroups],
117258945Sroberto				 pTmpLBuf->lgrui0_name, retlen);
118258945Sroberto			GroupList[*totalGroups][retlen] = '\0';
119258945Sroberto			if (strcmp(GroupList[*totalGroups], "None") == 0)
120258945Sroberto				free(GroupList[*totalGroups]);
121258945Sroberto			else
122258945Sroberto				(*totalGroups)++;
123258945Sroberto			pTmpLBuf++;
124258945Sroberto		}
125258945Sroberto	}
126258945Sroberto	/* Free the allocated memory. */
127258945Sroberto	if (pBuf != NULL)
128258945Sroberto		NetApiBufferFree(pBuf);
129258945Sroberto
130280849Scy
131258945Sroberto	/*
132258945Sroberto	 * Call the NetUserGetGroups function, specifying level 0.
133258945Sroberto	 */
134258945Sroberto	nStatus = NetUserGetGroups(NULL,
135280849Scy			      user,
136280849Scy			      dwLevel,
137280849Scy			      (LPBYTE*)&pgrpBuf,
138280849Scy			      dwPrefMaxLen,
139280849Scy			      &dwEntriesRead,
140280849Scy			      &dwTotalEntries);
141258945Sroberto	/*
142258945Sroberto	 * See if the call succeeds,
143258945Sroberto	 */
144258945Sroberto	if (nStatus != NERR_Success) {
145258945Sroberto		if (nStatus == ERROR_ACCESS_DENIED)
146258945Sroberto			return (ISC_R_NOPERM);
147258945Sroberto		if (nStatus == ERROR_MORE_DATA)
148258945Sroberto			return (ISC_R_NOSPACE);
149258945Sroberto		if (nStatus == NERR_UserNotFound)
150258945Sroberto			dwEntriesRead = 0;
151258945Sroberto	}
152280849Scy
153258945Sroberto	if (pgrpBuf != NULL) {
154258945Sroberto		pTmpBuf = pgrpBuf;
155258945Sroberto		/*
156258945Sroberto		 * Loop through the entries
157258945Sroberto		 */
158280849Scy		 for (i = 0;
159258945Sroberto		     (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
160258945Sroberto			assert(pTmpBuf != NULL);
161258945Sroberto
162258945Sroberto			if (pTmpBuf == NULL)
163258945Sroberto				break;
164258945Sroberto			retlen = wcslen(pTmpBuf->grui0_name);
165258945Sroberto			GroupList[*totalGroups] = (char *) malloc(retlen +1);
166258945Sroberto			if (GroupList[*totalGroups] == NULL)
167258945Sroberto				return (ISC_R_NOMEMORY);
168258945Sroberto
169258945Sroberto			retlen = wcstombs(GroupList[*totalGroups],
170258945Sroberto				 pTmpBuf->grui0_name, retlen);
171258945Sroberto			GroupList[*totalGroups][retlen] = '\0';
172258945Sroberto			if (strcmp(GroupList[*totalGroups], "None") == 0)
173258945Sroberto				free(GroupList[*totalGroups]);
174258945Sroberto			else
175258945Sroberto				(*totalGroups)++;
176258945Sroberto			pTmpBuf++;
177258945Sroberto		}
178258945Sroberto	}
179258945Sroberto	/*
180258945Sroberto	 * Free the allocated memory.
181258945Sroberto	 */
182258945Sroberto	if (pgrpBuf != NULL)
183258945Sroberto		NetApiBufferFree(pgrpBuf);
184258945Sroberto
185258945Sroberto	return (ISC_R_SUCCESS);
186258945Sroberto}
187