Link to home
Start Free TrialLog in
Avatar of PJLeyther
PJLeyther

asked on

Query Username membership of NT groups?

Hi All hope you can help

Our users are logging on to a
client/server app using NT (4.0)
account information. I need to see if
the user is a member of a
particular group. As the client is
running on Win 95 the API functions
need to be compliant. Can you point
me to the rel source (or maybe even
a component).

Dev Env: Delphi 5 enterprise on Win 98

thanks

PJLeyther

Avatar of Madshi
Madshi

Difficult question. Read this text:

"http://www.wsb.poznan.pl/~pawel/vb/www.mvps.org/win32/network/nt95.html#Section 3: Radmin32 to the Rescue"

Does that help?

NetUserGetGroups is the API.

Regards, Madshi.
ASKER CERTIFIED SOLUTION
Avatar of CameronCole
CameronCole

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Cameron, it seems that your stuff only works under NT. But PJLeyther needs it for win9x...   :-(

Regards, Madshi.
Avatar of RBertora
Listening..
Avatar of PJLeyther

ASKER

Thanks for the prompt replys, Madshi and CameronCole. I will investigate your responses. Speak to you soon.

regards

pjleyther
It can work under win9x.  You just need to copy NetAPI32.DLL to the machine.  Some of the write functions will not work correctly, but the reads should be fine.

If you need the write functions, write a server side process on NT that the win9x client calls.  You can use tserversocket and tclientsocket.  If you are lazy, you can just spit out a tstringslist to a file every so often.  Getting the groups otherwise will be difficult at best.  
listen
Hi,

I am answering this question so it can be saved as a PAQ.

PJLeyther wishes to split the points equally between Madshi and CameronCole.

I have issued separate questions for each expert in this topic area.

IanB
Community Support @ Experts Exchange
Hi Madshi, CameronCole

I have managed to solve my problem with the help of you both. Because of this, and I hope you both agree, I have arranged that the points be split between you.

Thanks Madshi your URL pointer has been really usefull. Thanks also CameronCole for your example app. My task only involved reading the SAM so exerts of your code together with the posted information proved adequate.

Thanks again

PJLeyther :-)

That's nice, that you got it working... Hmmm... Would you mind sharing your results with us?    :-)

Regards, Madshi.
Madshi

Not at all. Will post very soon keep listening. I have only opened this at the end of my working day (UK) ... other (must dooos - under the thumb and other expressions come to mind) things on tonight.

regards

PJLeyther
Thanx...   :-)   I'll keep listening...
Hi Madshi, CameronCole

As promised.

Our task was to find the current users NT Account membership groups available by calls from client software running on Win 95 - all reads, no writes.

Our results were satisfied with the following...

A component has been written using Delphi 5 enterpise on Win 98 with all calls declared/defined within the same pas file. Hope it helps.

BTW: We wont be held responsible for this code... etc, etc, etc... you know the score.


unit insNTSecurity;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

procedure NetApiBufferFree(pBuffer: pByte); stdcall;
   external 'radmin32.DLL' name 'NetApiBufferFree';

function NetGetDCName(pServerName: pChar; pDomainName: pChar;
   pBuffer: pByte): DWord; stdcall;
   external 'radmin32.DLL' name 'NetGetDCNameA';

function NetUserGetInfo(pServerName: pWideChar; pUserName: pWideChar;
   wLevel: DWord; pBuffer: PByte): DWord; stdcall;
   external 'radmin32.DLL' name 'NetUserGetInfo';

function NetGroupEnum(pServerName: pWideChar; wLevel: DWord;
   pBuffer: pByte; wBufLen: DWord; wpEntriesRead: pDWord;
   wpTotalEntries: pDWord; wpResume_Handle: pDWord): DWord; stdcall;
   external 'radmin32.DLL' name 'NetGroupEnum';

function NetUserGetGroups(pServerName: pWideChar; pUserName: pWideChar;
   wLevel: DWord; pBuffer: PByte; wBufLen: DWord; wpEntriesRead: pDWord;
   wpTotalEntries: pDWord): DWord; stdcall;
   external 'radmin32.DLL' name 'NetUserGetGroups';

type
   TUserInfo1 = packed record
      usri1_name: pWideChar;
      usri1_password: pWideChar;
      usri1_password_age: DWord;
      usri1_priv: DWord;
      usri1_home_dir: pWideChar;
      usri1_comment: pWideChar;
      usri1_flags: DWord;
      usri1_script_path: pWideChar;
   end;
   PUserInfo1 = ^TUserInfo1;

   TGroupInfo1 = packed record
      grpi1_name: pWideChar;
      grpi1_comment: pWideChar;
   end;
   PGroupInfo1 = ^TGroupInfo1;

type
  TUserDetails = class(TPersistent)
  private
     FName : String;
     FPassword : String;
     FPasswordAge : DWord;
     FPriv : DWord;
     FHomeDir : String;
     FComment : string;
     FFlags : DWord;
     FScriptPath : String;
     FGroups : TStrings;
  protected
  public
    constructor Create;
    destructor Destroy;
  published
    property Name : String Read FName write FName;
    property Password : String read FPassword write FPassword;
    property PasswordAge : DWord read FPasswordAge write FPasswordAge;
    property Priv : DWord read FPriv write FPriv;
    property HomeDir : String read FHomeDir write FHomeDir;
    property Comment : String read FComment write FComment;
    property Flags : Dword read FFlags write FFlags;
    property ScriptPath : String read FScriptPath write FScriptPath;
    property Groups : TStrings read FGroups write FGroups;
  end;

  TINSNTSecurity = class(TComponent)
  private
    FPDCName : String;
    FUserName : String;
    FUserDetails : TUserDetails;
    FGroups      : TStrings;
    Procedure SetFPDCName(Value:String);
    Procedure SetUserName(Value:String);
  protected
    { Protected declarations }
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property PDCName : String Read FPDCName write SetFPDCName;
    property UserName : String read FUserName write SetUserName;
    property UserDetails : TUserDetails read FUserDetails write FUserDetails;
    property Groups : TStrings read FGroups write FGroups;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Insight Approved', [TINSNTSecurity]);
end;

constructor TUserDetails.Create;
begin
   inherited Create;
   FGroups:=TStringList.Create;
end;

destructor TUserDetails.Destroy;
begin
   FGroups.Free;
   inherited Destroy;
end;

constructor TINSNTSecurity.Create(AOwner : TComponent);
var
   wResult: DWord;
   pBuffer: Pointer;
   wBufLen  : DWord;
   wTotalEntries: DWord;
   wEntriesRead: DWord;
   wLevel: DWord;
   wResumeHandle: DWord;
   iLoop : Integer;
   GroupRecInfo: PGroupInfo1;
begin
   inherited Create(AOwner);
   FUserDetails:=TUserDetails.Create;
   FGroups:=TStringList.Create;
   pBuffer:=Nil;
   wResult:=NetGetDCName('','',@pBuffer);
   if wResult=0 then begin
      FPDCName:=strpas(pBuffer);
   end else
      FPDCName:='NA';
   // Free the Buffer
   NetApiBufferFree(pBuffer);

   // now go get the group list
   FGroups.Clear;
   wBufLen:=64000;
   wEntriesRead := 0;
   wTotalEntries := 0;
   wResumeHandle := 0;
   wLevel:=1;
   wResult := NetGroupEnum(pwidechar(WideString(FPDCName)),wLevel, @pBuffer, wBufLen, @wEntriesRead, @wTotalEntries, @wResumeHandle);
   if wResult=0 then begin
      for iLoop := 0 to wEntriesRead - 1 do begin
         GroupRecInfo := PGroupInfo1(LongInt(pBuffer) + (iLoop * SizeOf(TGroupInfo1)));
         FGroups.Add(string(GroupRecInfo^.grpi1_name)+#9+string(GroupRecInfo^.grpi1_comment));
      end;
   end;
end;

destructor TINSNTSecurity.Destroy;
begin
   FUserDetails.Free;
   FGroups.Free;
   inherited Destroy;
end;

procedure TINSNTSecurity.SetFPDCName(Value:String);
begin
   // Just ignore the value
end;

procedure TINSNTSecurity.SetUserName(Value:String);
var
   wResult: DWord;
   pBuffer: Pointer;
   UserRecInfo: PUserInfo1;
   wBufLen  : DWord;
   wTotalEntries: DWord;
   wEntriesRead: DWord;
   wLevel: DWord;
   wResumeHandle: DWord;
   iLoop : Integer;
   GroupRecInfo: PGroupInfo1;
begin
   // Go Get the NT User Info
   FUserName:=Value;

   wResult:=NetUserGetInfo(pWideChar(WideString(FPDCName)),pwidechar(WideString(FUserName)),1,@pBuffer);
   if wResult=0 then begin
      UserRecInfo := PUserInfo1(LongInt(pBuffer));
      FUserDetails.FName:=UserRecInfo^.usri1_name;
      FUserDetails.FPassword:=UserRecInfo^.usri1_password;
      FUserDetails.FHomeDir:=UserRecInfo^.usri1_home_dir;
      FUserDetails.FPasswordAge:=UserRecInfo^.usri1_password_age;
      FUserDetails.FPriv:=UserRecInfo^.usri1_priv;
      FUserDetails.FComment:=UserRecInfo^.usri1_comment;
      FUserDetails.FFlags:=UserRecInfo^.usri1_flags;
      FUserDetails.FScriptPath:=UserRecInfo^.usri1_script_path;
      NetApiBufferFree(pBuffer);
      // go get users groups
      FUserDetails.Groups.Clear;
      wBufLen:=64000;
      wEntriesRead := 0;
      wTotalEntries := 0;
      wResumeHandle := 0;
      wLevel:=1;
      wResult := NetGroupEnum(pwidechar(WideString(FPDCName)),wLevel, @pBuffer, wBufLen, @wEntriesRead, @wTotalEntries, @wResumeHandle);
      if wResult=0 then begin
         for iLoop := 0 to wEntriesRead - 1 do begin
            GroupRecInfo := PGroupInfo1(LongInt(pBuffer) + (iLoop * SizeOf(TGroupInfo1)));
            FUserDetails.Groups.Add(string(GroupRecInfo^.grpi1_name)+#9+string(GroupRecInfo^.grpi1_comment));
         end;
      end;
      NetApiBufferFree(pBuffer);
   end else begin
      FUserDetails.Name:='NA';
      FUserDetails.HomeDir:='NA';
      FUserDetails.Password:='NA';
      FUserDetails.FPasswordAge:=0;
      FUserDetails.FPriv:=0;
      FUserDetails.FComment:='NA';
      FUserDetails.FFlags:=0;
      FUserDetails.FScriptPath:='NA';
      FUserDetails.Groups.Clear;
   end;
end;

end.

(with thanks to Darren who built the component while I was busy on something else)


Thank you...   :-)
Madshi, CameronCole

No problem. I hope we can do business in the future.

Thanks again

PJLeyther