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

PJLeytherAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MadshiCommented:
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.
0
CameronColeCommented:
This takes some real code, however you are in luck.  I have converted all the API calls and created an object/application that does just what you want (it also does user maintenance).  You can find it at http://www.msigroup.com/cameron/ftp/groups.zip

Hope it helps, C.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MadshiCommented:
Hi Cameron, it seems that your stuff only works under NT. But PJLeyther needs it for win9x...   :-(

Regards, Madshi.
0
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

RBertoraCommented:
Listening..
0
PJLeytherAuthor Commented:
Thanks for the prompt replys, Madshi and CameronCole. I will investigate your responses. Speak to you soon.

regards

pjleyther
0
CameronColeCommented:
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.  
0
yk030299Commented:
listen
0
ianBCommented:
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
0
PJLeytherAuthor Commented:
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 :-)

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

Regards, Madshi.
0
PJLeytherAuthor Commented:
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
0
MadshiCommented:
Thanx...   :-)   I'll keep listening...
0
PJLeytherAuthor Commented:
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)


0
MadshiCommented:
Thank you...   :-)
0
PJLeytherAuthor Commented:
Madshi, CameronCole

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

Thanks again

PJLeyther


0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.