[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apr-dev
Subject:    Re: Getting the groups a user belongs to
From:       William R Speirs <bill.speirs () gmail ! com>
Date:       2010-12-23 21:08:38
Message-ID: 4D13BA56.4030603 () gmail ! com
[Download RAW message or body]

I took a first stab at the Windows code for this... it's ugly. There is a lot of 
apr_wchar_t* <-> char* conversion code. Is there an easier way to do this?

If not, then maybe it would be helpful to create two functions with the 
following signatures that do all of the string length and allocation work for you:

apr_wchar_t* apr_conv_utf8_to_ucs2(char *str, apr_pool_t *p);
char* apr_conv_ucs2_to_utf8(apr_wchar_t *str, apr_pool_t *p);


Here is my code, not sure if this name is 100% consistent with the rest of the 
codebase:

APR_DECLARE(apr_status_t) apr_uid_groups_get(apr_gid_t **groups, int *ngroup,
											 const char *username, apr_pool_t *p)
{
#ifdef _WIN32_WCE
	return APR_ENOTIMPL;
#else
	GROUP_USERS_INFO_0 *pGroups = NULL;
	DWORD entriesRead = 0;
	DWORD totalEntries = 0;
	NET_API_STATUS status;
	FIXED_INFO *pFixedInfo = NULL;
	ULONG infoSize = 0;
	DWORD i;

	apr_wchar_t *wUsername;
	apr_size_t wUsernameLen;
	
	apr_wchar_t *fullDomain;
	apr_size_t fullDomainLen;
	apr_size_t domainLen;

	char *groupName;

	// first call is to get the size
	status = GetNetworkParams(pFixedInfo, &infoSize);
	
	pFixedInfo = (FIXED_INFO*)apr_palloc(p, infoSize);

	// now make the actual call
	status = GetNetworkParams(pFixedInfo, &infoSize);

//	printf("DOMAIN: %s\n", pFixedInfo->DomainName);

	if(NERR_Success != status)
		return APR_EINVAL;

	// convert the username to an apr_wchar_t
	domainLen = lstrlen(username);	// re-use of var here
	wUsernameLen = lstrlen(username) * sizeof(apr_wchar_t);
	wUsername = (apr_wchar_t*)apr_palloc(p, wUsernameLen);
	apr_conv_utf8_to_ucs2(username, &domainLen, wUsername, &wUsernameLen);

	// get the length of the domain string
	domainLen = lstrlenA(pFixedInfo->DomainName);

	// if there is no domain name, then get local groups
	if(0 == domainLen) {
//		printf("NO DOMAIN\n");

		status = NetUserGetLocalGroups(NULL, wUsername, 0,
                                                LG_INCLUDE_INDIRECT,
                                                (LPBYTE*) &pGroups,
					       MAX_PREFERRED_LENGTH,
                                                &entriesRead, &totalEntries);

		if(NERR_Success != status) {
			NetApiBufferFree(pGroups);
			return APR_EINVAL;
		}

	} else {	// we have a domain, get those groups
		domainLen = lstrlen(pFixedInfo->DomainName);
		fullDomainLen = (2 + domainLen) * sizeof(apr_wchar_t);
		fullDomain = (apr_wchar_t*)apr_palloc(p, fullDomainLen);

		// add the \\ to the start of the domain
		fullDomain[0] = '\\';
		fullDomain[1] = '\\';
		fullDomainLen -= 2;

		// convert over to an apr_wchar_t
		apr_conv_utf8_to_ucs2(pFixedInfo->DomainName, &domainLen,
                                       fullDomain+2, &fullDomainLen);

		status = NetUserGetGroups(fullDomain, wUsername, 0,
                                           (LPBYTE*) &pGroups,
					  MAX_PREFERRED_LENGTH,
                                           &entriesRead, &totalEntries);

		if(NERR_Success != status) {
			NetApiBufferFree(pGroups);
			return APR_EINVAL;
		}
	}
	
	// allocate space for all of the apr_gid_t
	*groups = (apr_gid_t*)apr_palloc(p, entriesRead);
	*ngroup = entriesRead;

	// we have all of the groups, but as strings
	for(i=0; i < entriesRead; ++i) {
		printf("GROUP: %S\n", pGroups[i].grui0_name);

		// convert the wchar_t group name to a char* group name
		domainLen = lstrlenW(pGroups[i].grui0_name);
		wUsernameLen = domainLen * sizeof(char);
		groupName = (char*)apr_palloc(p, wUsernameLen);
		apr_conv_ucs2_to_utf8(pGroups[i].grui0_name, &domainLen,
                                       groupName, &wUsernameLen);

		apr_gid_get(*groups[i], groupName, p);
	}

	// free the memory associated with the groups
	NetApiBufferFree(pGroups);

	return APR_SUCCESS;

#endif
}



Thoughts?

Bill-

On 12/13/2010 09:33 AM, Bill Speirs wrote:
>>> The other issue is that on Windows I get back a char* for the groups; whereas, on
>>> Unix/Linux I get back a gid list. Is there a preference? Would people rather a function
>>> that returns a gid list or a char* list?
>>
>> Well, we should treat them as apr_gid_t, which on win32 would devolve to a pointer
>> to a full UUID of the appropriate group (and we then unwind the identifier into a
>> human-readable string with the appropriate apr_group_name_get function).
>
> In Linux this is a non-issue as the function naturally returns
> apr_gid_t; whereas, with Windows I only get back a char* for the
> group. I can call LookupAccountName on each name to get the
> SID/apr_gid_t. If there is a function to get apr_gid_ts for the groups
> a user is a member of, I am unaware of such a function.
>
> Bill-
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic