narkive is for sale. Interested? (dismiss)
Discussion:
Allocating Lsa_Token_Information_V2 properly, and general questions regarding LsaApLogonUser and AP's
(too old to reply)
WakA
2004-07-17 17:20:24 UTC
Permalink
As i am currently writing a custom authentication package i'm running into
some problems (ofcourse). One of these is the usage of this struct. I'm
using it in the LsaApLogonUser function and trying to fill the struct with
information so i can return it.
How exactly can i allocate this structure properly, since the
LSA_TOKEN_INFORMATION_V2 is typedef as being

typedef LSA_TOKEN_INFORMATION_V1 LSA_TOKEN_INFORMATION_V2,
*PLSA_TOKEN_INFORMATION_V2;

How exactly if V2 is a monolithically allocated structure can i allocate
everything in the right order. That is i'm assuming everything is a
contiguous block of all the info the size of all the structures in
tokeninformation.

Question number 2 - The Profile buffer:
How am i to actually allocate this buffer and pass it back to my
LsaLogonUser which i am calling from my own GINA. This is currently how i am
allocating.

error =
gDispatchTable->AllocateClientBuffer(ClientRequest,PROFILE_BUFFER_LENGTH,*Pr
ofileBuffer);
if (!error) {
*ProfileBufferLength = PROFILE_BUFFER_LENGTH;
wcscpy((wchar_t*)ProfileBuffer,L"Dit dan weer wel");
}

Since the AllocateClientBuffer must be used (according to msdn) the memory
is a base address from the clients point of view. Is this allocated now in
the calling function to LsaApLogonUser or not?

Question number 3 - Responsibilities of the authentication
package/LsaApLogonUser:

What are all the responsibilities of this function (LsaApLogonUser),
currently i understand it to be:
1-Allocate ClientBuffer
3-Fill TokenInformation struct (be it V1 or V2)
2-AllocateLocallyUniqueId(LogonId)
4-CreateLogonSession(LogonID)

Something tells me i am still missing something since LsaLogonUser returns
998 or "Invalid access to memory location. "(The NTSTATUS converted to
windows error code). And i cannot see where i made this error.

Well, you made it through this post..thanks for that anyway :)

Chris
Richard Ward
2004-07-20 07:01:12 UTC
Permalink
Post by WakA
How exactly can i allocate this structure properly, since the
LSA_TOKEN_INFORMATION_V2 is typedef as being
typedef LSA_TOKEN_INFORMATION_V1 LSA_TOKEN_INFORMATION_V2,
*PLSA_TOKEN_INFORMATION_V2;
How exactly if V2 is a monolithically allocated structure can i allocate
everything in the right order. That is i'm assuming everything is a
contiguous block of all the info the size of all the structures in
tokeninformation.
You compute the size of the structure, plus all the sizes of the referenced
structures, allocate once, and then fill it in. Sometimes this is referred
to as
hand-marshalling. Something like:

PLSA_TOKEN_INFORMATION_V2 TokenInfo ;
PUCHAR Scratch ;

...
TokenInfo = LsaFuncs->AllocateLsaHeap( x );
Scratch = (PUCHAR) (TokenInfo + 1);
TokenInfo->ExpirationTime = (time)
TokenInfo->User.User.Sid = (PSID) Scratch ;
CopySid( TokenInfo->User.User.Sid, <sid you determined> )
Scratch += SidLength( TokenInfo->User.User.Sid );

etc.
Post by WakA
How am i to actually allocate this buffer and pass it back to my
LsaLogonUser which i am calling from my own GINA. This is currently how i am
allocating.
error =
gDispatchTable->AllocateClientBuffer(ClientRequest,PROFILE_BUFFER_LENGTH,*Pr
ofileBuffer);
if (!error) {
*ProfileBufferLength = PROFILE_BUFFER_LENGTH;
wcscpy((wchar_t*)ProfileBuffer,L"Dit dan weer wel");
}
Since the AllocateClientBuffer must be used (according to msdn) the memory
is a base address from the clients point of view. Is this allocated now in
the calling function to LsaApLogonUser or not?
Build up your profile buffer in the LSA space. Then,

PVOID ClientBuffer ;
Status = LsaFuncs->AllocateClientBuffer( ClientRequest,
PROFILE_BUFFER_LENGTH, &ClientBuffer );
if ( NT_SUCCESS( Status ) )
{
Status = LsaFuncs->CopyToClientBuffer( ClientRequest,
PROFILE_BUFFER_LENGTH, ClientBuffer, ProfileBufferInLsaSpace );
*ProfileBuffer = ClientBuffer ;
*ProfileBufferSize = PROFILE_BUFFER_LENGTH ;
}
Post by WakA
Question number 3 - Responsibilities of the authentication
What are all the responsibilities of this function (LsaApLogonUser),
1-Allocate ClientBuffer
3-Fill TokenInformation struct (be it V1 or V2)
2-AllocateLocallyUniqueId(LogonId)
4-CreateLogonSession(LogonID)
The authentication package has the responsibility to authenticate the
user, determine the group memberships, distribute credentials to the
other packages, and create a profile for the user to return to the
caller of LsaLogonUser(). You will need to create a logon session,
and you will need to fill in the token information so that the LSA can
create the token and process the machine specific policy.
WakA
2004-07-20 12:58:29 UTC
Permalink
Thanks for the excellent response, but i still have some questions.
Post by Richard Ward
PLSA_TOKEN_INFORMATION_V2 TokenInfo ;
PUCHAR Scratch ;
...
TokenInfo = LsaFuncs->AllocateLsaHeap( x );
Scratch = (PUCHAR) (TokenInfo + 1);
TokenInfo->ExpirationTime = (time)
TokenInfo->User.User.Sid = (PSID) Scratch ;
CopySid( TokenInfo->User.User.Sid, <sid you determined> )
Scratch += SidLength( TokenInfo->User.User.Sid );
Wouldn't you increment scratch afer ExperationTime as well (with
sizeof(LARGE_INTEGER) in this case). And when i assign scratch to user.sid
what happens to User.Attributes (also part of the struct) when i copysid,
doesn't that function overwrite user.attributes, or do i have to reallocate
that value too?

Also i'm getting an access violation returned from LsaLogonUser when i call
my package, is this the result of my not (yet) properly allocating
tokenstructure?

Making progress at last,

Chris :)
Richard Ward
2004-07-21 06:17:30 UTC
Permalink
Post by WakA
Thanks for the excellent response, but i still have some questions.
Post by Richard Ward
PLSA_TOKEN_INFORMATION_V2 TokenInfo ;
PUCHAR Scratch ;
...
TokenInfo = LsaFuncs->AllocateLsaHeap( x );
Scratch = (PUCHAR) (TokenInfo + 1);
TokenInfo->ExpirationTime = (time)
TokenInfo->User.User.Sid = (PSID) Scratch ;
CopySid( TokenInfo->User.User.Sid, <sid you determined> )
Scratch += SidLength( TokenInfo->User.User.Sid );
Wouldn't you increment scratch afer ExperationTime as well (with
sizeof(LARGE_INTEGER) in this case). And when i assign scratch to user.sid
what happens to User.Attributes (also part of the struct) when i copysid,
doesn't that function overwrite user.attributes, or do i have to reallocate
that value too?
Well, no. Are you familiar with how pointers work? Walk through the
Post by WakA
Post by Richard Ward
TokenInfo = LsaFuncs->AllocateLsaHeap( x );
TokenInfo points to a chunk of memory of size x, where x is the sum of
all the sizes of all the goo. It is at least sizeof(
LSA_TOKEN_INFORMATION_V2),
and likely much larger.
Post by WakA
Post by Richard Ward
Scratch = (PUCHAR) (TokenInfo + 1);
Scratch now points to an aligned spot, just past the end of the space needed
to hold a LSA_TOKEN_INFORMATION_V2. There is the fixed size structure,
pointed to by the TokenInfo pointer, and there is the unstructured variable
space,
now pointed to by Scratch.
Post by WakA
Post by Richard Ward
TokenInfo->ExpirationTime = (time)
This updates a field in the fixed portion, ths LSA_TOKEN_INFORMATION_V2
structure.
Post by WakA
Post by Richard Ward
TokenInfo->User.User.Sid = (PSID) Scratch ;
This also updates a field in the fixed portion. It sets the pointer there
to the
start of the unstructured space.
Post by WakA
Post by Richard Ward
CopySid( TokenInfo->User.User.Sid, <sid you determined> )
Copies memory from your variable, to the unstructured space.
Post by WakA
Post by Richard Ward
Scratch += SidLength( TokenInfo->User.User.Sid );
Updates the pointer to the unstructured section to the next free spot.
Post by WakA
Also i'm getting an access violation returned from LsaLogonUser when i call
my package, is this the result of my not (yet) properly allocating
tokenstructure?
That would be my guess. You can set pageheap on the LSA process to catch
this, or use the debugger to dump the structure that you are returning to
verify
that it is valid.
WakA
2004-07-21 14:59:40 UTC
Permalink
"> Well, no. Are you familiar with how pointers work? Walk through the
Post by Richard Ward
Post by Richard Ward
Scratch = (PUCHAR) (TokenInfo + 1);
Scratch now points to an aligned spot, just past the end of the space needed
to hold a LSA_TOKEN_INFORMATION_V2. There is the fixed size structure,
pointed to by the TokenInfo pointer, and there is the unstructured variable
space,
now pointed to by Scratch.
Ah right, i thought the fixed structure was dynamically distributed over de memory allocation..which is a very weird thing to think..

Still doesn't work though in my case..i'm gonna paste my whole allocation here, i don't have any other ideas what i might be. I hope you can (and will :P) shed some light on it.

*TokenInformationType = LsaTokenInformationV2;

if (*TokenInformationType == LsaTokenInformationV2) {
PLSA_TOKEN_INFORMATION_V2 aTokenInformation = 0; //switched to V2 after XP functionality broken
PSID userSid = 0;
PSID groupSid = 0;

userSid = GetSidFromName(L"Administrator",L"");
AllocateAndInitializeSid(&sidAuthority,2,SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,&groupSid);

if( !userSid || !groupSid)
D(("Failed to initialize either userSid or groupSid"));
aTokenInformation = gDispatchTable->AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V2)+
sizeof(TOKEN_GROUPS)+ sizeof(SID_AND_ATTRIBUTES)*(GroupCount -1)//dynamically determine the size of the trailing array by extending the memory
+ GetLengthSid(userSid)
+ GetLengthSid(groupSid)*2
);
if (!aTokenInformation)
error = STATUS_INSUFFICIENT_RESOURCES;


if (!error) {
PUCHAR scratch;
scratch = (PUCHAR)(aTokenInformation+1); //now points to unstructured variable space after
//the TOKEN_INFORMATION struct

aTokenInformation->ExpirationTime.QuadPart = 20202002045553; //expiration time in seconds.


if (userSid && groupSid) {

aTokenInformation->User.User.Attributes = SE_GROUP_LOGON_ID;

aTokenInformation->User.User.Sid = (PSID)scratch;
CopySid(GetLengthSid(userSid),aTokenInformation->User.User.Sid,userSid);
scratch += GetLengthSid(aTokenInformation->User.User.Sid);

aTokenInformation->Groups = (PTOKEN_GROUPS)scratch;
aTokenInformation->Groups->GroupCount = GroupCount;
aTokenInformation->Groups->Groups[0].Attributes = SE_GROUP_LOGON_ID; //already allocated with 1 as array size, so this is a trick to dynamically size the array

scratch += sizeof(TOKEN_GROUPS);
aTokenInformation->Groups->Groups[0].Sid = scratch;
//AllocateAndInitializeSid(&sidAuthority,1,SECURITY_INTERACTIVE_RID,0,0,0,0,0,0,0,&tempSid);



CopySid(GetLengthSid(groupSid),aTokenInformation->Groups->Groups[0].Sid,groupSid);
scratch += GetLengthSid(groupSid);

aTokenInformation->PrimaryGroup.PrimaryGroup = (PSID)scratch;
CopySid(GetLengthSid(aTokenInformation->Groups->Groups[0].Sid),aTokenInformation->PrimaryGroup.PrimaryGroup, aTokenInformation->Groups->Groups[0].Sid);

aTokenInformation->Owner.Owner = 0;
aTokenInformation->DefaultDacl.DefaultDacl = 0;
aTokenInformation->Privileges = 0;

*TokenInformation = aTokenInformation;
LocalFree(userSid); //release from allocation in GetSidFromName
D(("TokenInformation set"));
}
}
m***@gmail.com
2018-06-20 06:12:01 UTC
Permalink
Post by WakA
"> Well, no. Are you familiar with how pointers work? Walk through the
Post by Richard Ward
Post by Richard Ward
Scratch = (PUCHAR) (TokenInfo + 1);
Scratch now points to an aligned spot, just past the end of the space needed
to hold a LSA_TOKEN_INFORMATION_V2. There is the fixed size structure,
pointed to by the TokenInfo pointer, and there is the unstructured variable
space,
now pointed to by Scratch.
Ah right, i thought the fixed structure was dynamically distributed over de memory allocation..which is a very weird thing to think..
Still doesn't work though in my case..i'm gonna paste my whole allocation here, i don't have any other ideas what i might be. I hope you can (and will :P) shed some light on it.
*TokenInformationType = LsaTokenInformationV2;
if (*TokenInformationType == LsaTokenInformationV2) {
PLSA_TOKEN_INFORMATION_V2 aTokenInformation = 0; //switched to V2 after XP functionality broken
PSID userSid = 0;
PSID groupSid = 0;
userSid = GetSidFromName(L"Administrator",L"");
AllocateAndInitializeSid(&sidAuthority,2,SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,&groupSid);
if( !userSid || !groupSid)
D(("Failed to initialize either userSid or groupSid"));
aTokenInformation = gDispatchTable->AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V2)+
sizeof(TOKEN_GROUPS)+ sizeof(SID_AND_ATTRIBUTES)*(GroupCount -1)//dynamically determine the size of the trailing array by extending the memory
+ GetLengthSid(userSid)
+ GetLengthSid(groupSid)*2
);
if (!aTokenInformation)
error = STATUS_INSUFFICIENT_RESOURCES;
if (!error) {
PUCHAR scratch;
scratch = (PUCHAR)(aTokenInformation+1); //now points to unstructured variable space after
//the TOKEN_INFORMATION struct
aTokenInformation->ExpirationTime.QuadPart = 20202002045553; //expiration time in seconds.
if (userSid && groupSid) {
aTokenInformation->User.User.Attributes = SE_GROUP_LOGON_ID;
aTokenInformation->User.User.Sid = (PSID)scratch;
CopySid(GetLengthSid(userSid),aTokenInformation->User.User.Sid,userSid);
scratch += GetLengthSid(aTokenInformation->User.User.Sid);
aTokenInformation->Groups = (PTOKEN_GROUPS)scratch;
aTokenInformation->Groups->GroupCount = GroupCount;
aTokenInformation->Groups->Groups[0].Attributes = SE_GROUP_LOGON_ID; //already allocated with 1 as array size, so this is a trick to dynamically size the array
scratch += sizeof(TOKEN_GROUPS);
aTokenInformation->Groups->Groups[0].Sid = scratch;
//AllocateAndInitializeSid(&sidAuthority,1,SECURITY_INTERACTIVE_RID,0,0,0,0,0,0,0,&tempSid);
CopySid(GetLengthSid(groupSid),aTokenInformation->Groups->Groups[0].Sid,groupSid);
scratch += GetLengthSid(groupSid);
aTokenInformation->PrimaryGroup.PrimaryGroup = (PSID)scratch;
CopySid(GetLengthSid(aTokenInformation->Groups->Groups[0].Sid),aTokenInformation->PrimaryGroup.PrimaryGroup, aTokenInformation->Groups->Groups[0].Sid);
aTokenInformation->Owner.Owner = 0;
aTokenInformation->DefaultDacl.DefaultDacl = 0;
aTokenInformation->Privileges = 0;
*TokenInformation = aTokenInformation;
LocalFree(userSid); //release from allocation in GetSidFromName
D(("TokenInformation set"));
}
}
I have been working on custom auth package implementation for quite some days and been stuck on initialization of structs ProfileBuffer and TokenInformation. While searching on internet, I landed on your discussion regarding this on google groups where you posted your code as well.
Can you please guide me how to populate these structs with right content so that LsaApLogOnUser routine works perfectly?

Your help in this regard will be highly appreciated!

Loading...