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