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