Solved

Getting group information for a user

Posted on 2002-07-29
10
440 Views
Last Modified: 2013-11-20
I'm writing an application with Visual C++ 6.0 on Windows 2000.  I would like to determine user privileges based on a user being in a group.  For example, a user that logs in and that user is in the group TestAdmins.  In the applicatin, I want to be able to take the username that is logged in and find out if they are currently a member of the group TestAdmins.  I've read a little about ADSI but not sure if this is the way I should go.

Any help is truly appreciated.

0
Comment
Question by:jstephe1
  • 5
  • 4
10 Comments
 
LVL 12

Expert Comment

by:migel
ID: 7186005
Hi!
1. To get current user uou can use GetUserName API
2. to find User group you have to use NetUserGetGroups API
for example:

{
   LPGROUP_USERS_INFO_0 pBuf = NULL;
   DWORD dwLevel = 0;
   DWORD dwPrefMaxLen = -1;
   DWORD dwEntriesRead = 0;
   DWORD dwTotalEntries = 0;
   NET_API_STATUS nStatus;

   //
   // Call the NetUserGetGroups function, specifying level 0.
   //
   nStatus = NetUserGetGroups(NULL,
                              lpszUserName,
                              0,
                              (LPBYTE*)&pBuf,
                              dwPrefMaxLen,
                              &dwEntriesRead,
                              &dwTotalEntries);
   //
   // If the call succeeds,
   //
   if (nStatus == NERR_Success)
   {
      LPGROUP_USERS_INFO_0 pTmpBuf;
      DWORD i;
      DWORD dwTotalCount = 0;

      if ((pTmpBuf = pBuf) != NULL)
      {
         fprintf(stderr, "\nGlobal group(s):\n");
         //
         // Loop through the entries;
         //  print the name of the global groups
         //  to which the user belongs.
         //
         for (i = 0; i < dwEntriesRead; i++)
         {
            assert(pTmpBuf != NULL);

            if (pTmpBuf == NULL)
            {
               break;
            }

            //to get GroupName use:
            // pTmpBuf->grui0_name

            pTmpBuf++;
            dwTotalCount++;
         }
      }
      //
      // If all available entries were
      //  not enumerated, print the number actually
      //  enumerated and the total number available.
   }
   else
     // error occured!
       MessageBox();

   //
   // Free the allocated buffer.
   //
   if (pBuf != NULL)
      NetApiBufferFree(pBuf);
0
 

Author Comment

by:jstephe1
ID: 7186226
I implemented the GetUserName function like this:

TCHAR lpszUserName[250];
DWORD dwUserNameLength = 250;

GetUserName( lpszUserName, &dwUserNameLength );

I get the user name "Administrator" after the call.  I then did your if condition call to the NetUserGetGroups.  Everytime I call it it comes back NERR_UserNotFound.  Do I need to specify the server as the first parameter?  If so, how would I do that?

0
 
LVL 12

Expert Comment

by:migel
ID: 7187249
Hi!
it is strange I run this code and status is ok;
1. my code enumerate global users groups for local ones you need to use
NetUserGetLocalGroups
here is example that working for me (console APP):

#ifndef UNICODE
#define UNICODE
#endif

#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <lm.h>

int wmain(int argc, wchar_t *argv[])
{
   LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
   DWORD dwLevel = 0;
   DWORD dwFlags = LG_INCLUDE_INDIRECT ;
   DWORD dwPrefMaxLen = -1;
   DWORD dwEntriesRead = 0;
   DWORD dwTotalEntries = 0;
   NET_API_STATUS nStatus;
/*
   if (argc != 3)
   {
      fwprintf(stderr, L"Usage: %s \\\\ServerName UserName\n", argv[0]);
      exit(1);
   }
*/
     TCHAR lpszUserName[250];
     DWORD dwUserNameLength = 250;

     GetUserName( lpszUserName, &dwUserNameLength );   //
   nStatus = NetUserGetLocalGroups(NULL,
                                   lpszUserName,
                                   dwLevel,
                                   dwFlags,
                                   (LPBYTE *) &pBuf,
                                   dwPrefMaxLen,
                                   &dwEntriesRead,
                                   &dwTotalEntries);
   //
   // If the call succeeds,
   //
   if (nStatus == NERR_Success)
   {
      LPLOCALGROUP_USERS_INFO_0 pTmpBuf;
      DWORD i;
      DWORD dwTotalCount = 0;

      if ((pTmpBuf = pBuf) != NULL)
      {
         fprintf(stderr, "\nLocal group(s):\n");
         //
         // Loop through the entries and
         //  print the names of the local groups
         //  to which the user belongs.
         //
         for (i = 0; i < dwEntriesRead; i++)
         {
            assert(pTmpBuf != NULL);

            if (pTmpBuf == NULL)
            {
               fprintf(stderr, "An access violation has occurred\n");
               break;
            }

            wprintf(L"\t-- %s\n", pTmpBuf->lgrui0_name);

            pTmpBuf++;
            dwTotalCount++;
         }
      }
         //
         // If all available entries were
         //  not enumerated, print the number actually
         //  enumerated and the total number available.
         //
      if (dwEntriesRead < dwTotalEntries)
         fprintf(stderr, "\nTotal entries: %d", dwTotalEntries);
      //
      // Otherwise, just print the total.
      //
      printf("\nEntries enumerated: %d\n", dwTotalCount);
   }
   else
      fprintf(stderr, "A system error has occurred: %d\n", nStatus);
   //
   // Free the allocated memory.
   //
   if (pBuf != NULL)
      NetApiBufferFree(pBuf);

   return 0;
}
0
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 

Author Comment

by:jstephe1
ID: 7188025
still comes back with user not found.  Could I use ADSI to do the same thing?

I tried to implement some ADSI code but I get an undeclared identifier for IADsUser when I try to use it.  How do I get started with ADSI?
0
 
LVL 12

Expert Comment

by:migel
ID: 7188198
did you use UNICODE?
0
 
LVL 12

Expert Comment

by:migel
ID: 7188212
did you use UNICODE?
0
 

Author Comment

by:jstephe1
ID: 7188310
I put the #ifndef UNICODE.. statements in.  The only difference in our code is that I had to cast the lpszUserName variable to a (LPCWSTR).  Could that be causing it not to be found?
0
 

Expert Comment

by:JShaft
ID: 7188522
I've been trying this same code with the same problems. What I finally figured out is that casting lpszUserName is not enough. I put this code in there to perform the translation and it worked fine...
#include <windows.h>
#include <lm.h>
#include <stdio.h>
#pragma hdrstop

int main( void );

int main( void )
{
DWORD rc, pref, got, total;
GROUP_USERS_INFO_0 *buf;
TCHAR lpszUserName[250];
DWORD dwUserNameLength = 250;
wchar_t *user = new wchar_t[250];

GetUserName(lpszUserName, &dwUserNameLength);

for( int i=0;i<(int)dwUserNameLength;i++)
{
   user[i] = lpszUserName[i];
}

pref = 16;
buf = NULL;

do{
   pref *= 2;
   if( buf != NULL )
   {
      NetApiBufferFree(buf);
      buf = NULL;
   }
   rc = NetUserGetLocalGroups(NULL, user, 0, 0, (LPBYTE *) &buf, pref, &got, &total);
}while( rc == NERR_BufTooSmall || rc == ERROR_MORE_DATA );

if( rc != 0 )
{
   printf("Error %lu\n", rc);
   return 1;
}
for( rc=0;buf!=NULL && rc<got; rc++)
{
   printf("%S\n", buf[rc].grui0_name);
}

if( buf != NULL )
{
   NetApiBufferFree( buf );
}
}
0
 
LVL 12

Accepted Solution

by:
migel earned 200 total points
ID: 7188733
it is so strange
cite from MSDN:
"...Windows 2000 servers and workstations: If you call one of the affected functions on a Windows 2000 member server or workstation to perform a query, all authenticated users can view the information. Anonymous access is also possible if the RestrictAnonymous policy setting allows anonymous access. For updates, only Administrators and account operators can write information..."

hmm what about ADSI?
here is example how to achieve same for ADSI
HRESULT CheckUserGroups(IADsUser *pUser)
{
    IADsMembers *pGroups;
    HRESULT hr = S_OK;
    hr = pUser->Groups(&pGroups);
    pUser->Release();
    if (FAILED(hr)) return hr;

    IUnknown *pUnk;
    hr = pGroups->get__NewEnum(&pUnk);
    if (FAILED(hr)) return hr;
    pGroups->Release();

    IEnumVARIANT *pEnum;
    hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
    if (FAILED(hr)) return hr;

    pUnk->Release();

    // Now Enumerate
    BSTR bstr;
    VARIANT var;
    IADs *pADs;
    ULONG lFetch;
    IDispatch *pDisp;

    VariantInit(&var);
    hr = pEnum->Next(1, &var, &lFetch);
    while(hr == S_OK)
    {
        if (lFetch == 1)
        {
             pDisp = V_DISPATCH(&var);
             pDisp->QueryInterface(IID_IADs, (void**)&pADs);
             pADs->get_Name(&bstr);
             printf("Group belonged: %S\n",bstr);
             SysFreeString(bstr);
             pADs->Release();
        }
        VariantClear(&var);
        pDisp=NULL;
        hr = pEnum->Next(1, &var, &lFetch);
    };
    hr = pEnum->Release();
    return S_OK;
}

IADsUser *GetUserObject(LPWSTR uPath)
{
    IADsUser *pUser;
    HRESULT hr = ADsGetObject(uPath,IID_IADsUser,(void**)&pUser);
    if (FAILED(hr)) {return NULL;}
    BSTR bstr;
    hr = pUser->get_FullName(&bstr);
    printf("User: %S\n", bstr);
    SysFreeString(bstr);
    return pUser;
}

int main(int argc, char* argv[])
{
    HRESULT hr = CoInitialize(NULL);
    // form here your Account name (represented as *****)
    // in form: WinNT://Microsoft/*****,user
    IADsUser *pUser = GetUserObject(
                      L"WinNT://Microsoft/JSmith,user");
    pUser->AddRef();
    hr = CheckUserGroups(pUser);
    if(pUser) pUser->Release();
    CoUninitialize();
    return 0;
}
0
 

Author Comment

by:jstephe1
ID: 7190797
Thanks for all the help.  I used the ADSI version with some minor changes and it works.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
xyBalance chalenge 58 96
centeredAverage challenge 8 178
twoTwo  challenge 35 107
Problem to App 4 97
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question