You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Bill Speirs <bi...@gmail.com> on 2010/12/13 15:33:50 UTC

Re: dev Digest of: get.23632

On Fri, Dec 10, 2010 at 1:12 PM,  <de...@apr.apache.org> wrote:
> From: "William A. Rowe Jr." <wr...@rowe-clan.net>
> To: dev@apr.apache.org
> Date: Thu, 09 Dec 2010 22:09:20 -0600
> Subject: Re: Getting the groups a user belongs to
>
> It seems sensible, the only hassle is the performance penalty that could be assessed
> for hitting the domain server.  Can you check this out and benchmark it?

I can try, but what are you looking for specifically: Win Vs. Linux or
Domain Vs. No Domain?

Domain Vs. No Domain is going to be tough for me as my domain
controller and workstation are on the same network, so the latency
won't really show. Whereas, in a production environment that is under
heavy load, your mileage will greatly vary.

>> 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-

P.S. Sorry for the late response...

Re: Getting the groups a user belongs to

Posted by William R Speirs <bi...@gmail.com>.
Bump...

Haven't heard anything, but it was over the holidays so I figured most people 
had checked-out.

Thanks...

Bill-

On 12/23/2010 04:08 PM, William R Speirs wrote:
> 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-

Re: Getting the groups a user belongs to

Posted by William R Speirs <bi...@gmail.com>.
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-