Enumerating Unix users and groups from Windows

Corinna Vinschen corinna at vinschen.de
Fri Jul 25 15:11:16 GMT 2008


On Jul 25 16:28, Volker Lendecke wrote:
> On Thu, Jul 24, 2008 at 10:54:36AM +0200, Corinna Vinschen wrote:
> > For instance, when you call NetLocalGroupEnum on a Windows machine, you
> > get a list which contains accounts from different "domains" and with
> > different base SIDs, too.  Calling LookupAccountName afterwards shows
> > that clearly:
> > 
> >   NetLocalGroupEnum (MACHINE); LookupAccountName (Name)
> > 
> >   Name		      RID   Domain  SID
> >   -----------------  ----   ------- -------------------------------
> >   Administrators      544   BUILTIN S-1-5-32-544
> >   Backup Operators    551   BUILTIN S-1-5-32-551
> >   Guests	      546   BUILTIN S-1-5-32-546
> >   [...]
> >   Users		      545   BUILTIN S-1-5-32-545
> >   HelpServicesGroup  1001   MACHINE S-1-5-21-12345-67890-76543-1001
> > 
> > So it enumerates BUILTIN accounts as well as MACHINE accounts.
> > 
> > Samba could return the unix groups as local groups as well:
> 
> Well, not quite. Windows always has its SAM (the
> S-1-5-21-12345-6... thingy), and S-1-5-32-xx. Samba does
> this as well, so you should see the same output from a Samba
> box.

That's not what I see.  The NetLocalGroupEnum function returns with
success but with an empty group list when called on a Samba server.
This is with 3.0.30.

> Those two domains are expected by the Win32 client API,
> not more. We could try to experiment what Windows says when
> we expand the samr_EnumDomains RPC call. What's the easiest
> way to call the NetEnumUsers API call? Some vbs script? :-)

Sorry, but I'm Windows scripting illiterate.  What about just installing
Cygwin and building the below code with

  gcc -o nlge nlge.c -lnetapi32


Corinna

=== SNIP ===
#include <stdio.h>
#include <windows.h>
#include <lm.h>

char *
put_sid (PSID psid)
{
  static char s[256];
  char t[32];
  DWORD i;

  strcpy (s, "S-1-");
  sprintf (t, "%u", GetSidIdentifierAuthority (psid)->Value[5]);
  strcat (s, t);
  for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i)
    {
      sprintf(t, "-%lu", *GetSidSubAuthority (psid, i));
      strcat (s, t);
    }
  return s;
}

void
enum_local_groups (char *server)
{
  WCHAR servername[256];
  LOCALGROUP_INFO_0 *buffer;
  DWORD entriesread = 0;
  DWORD totalentries = 0;
  DWORD resume_handle = 0;
  DWORD rc, i;

  if (!server)
    return;
  mbstowcs (servername, server, 256);
  
  do
    {
      rc = NetLocalGroupEnum (servername, 0, (void *) &buffer,
			      MAX_PREFERRED_LENGTH, &entriesread,
			      &totalentries, &resume_handle);
      if (rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS)
	{
	  fprintf (stderr, "NetLocalGroupEnum error %lu\n", rc);
	  break;
	}
      for (i = 0; i < entriesread; i++)
      	{
          WCHAR domain_name[256];
          DWORD domname_len = 256;
          char psid_buffer[40];
          PSID psid = (PSID) psid_buffer;
          DWORD sid_length = 40;
          SID_NAME_USE acc_type;

          if (!LookupAccountNameW (servername, buffer[i].lgrpi0_name, psid,
                                   &sid_length, domain_name, &domname_len,
                                   &acc_type))
            {
              fprintf (stderr, "LookupAccountNameW (%ls) error %lu\n",
		       buffer[i].lgrpi0_name, GetLastError ());
              continue;
            }
          else if (acc_type == SidTypeDomain)
            {
              WCHAR domname[512];

              wcscpy (domname, domain_name);
              wcscat (domname, L"\\");
              wcscat (domname, buffer[i].lgrpi0_name);
              sid_length = 40;
              domname_len = 256;
              if (!LookupAccountNameW (servername, domname,
                                       psid, &sid_length,
                                       domain_name, &domname_len,
                                       &acc_type))
                {
		  fprintf (stderr, "LookupAccountNameW (%ls) error %lu\n",
			   domname, GetLastError ());
                  continue;
                }
            }
	  printf ("%ls\\%ls == %s\n", domain_name, buffer[i].lgrpi0_name,
				      put_sid (psid));

	}
      NetApiBufferFree (buffer);
    }
  while (rc == ERROR_MORE_DATA);
}

int
main (int argc, char **argv)
{
  if (argc != 2)
    {
      fprintf (stderr, "usage: %s server\n", argv[0]);
      return 1;
    }
  enum_local_groups (argv[1]);
  return 0;
}


More information about the samba-technical mailing list