xref: /NextBSD/contrib/ntp/lib/isc/win32/ntgroups.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
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 
50 isc_result_t
isc_ntsecurity_getaccountgroups(char * username,char ** GroupList,unsigned int maxgroups,unsigned int * totalGroups)51 isc_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