Solved

Getting group information for a user

Posted on 2002-07-29
10
437 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
 

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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
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.
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…

863 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now