537 lines
14 KiB
C
537 lines
14 KiB
C
#include "pch.h"
|
|
#include "samplerm.h"
|
|
|
|
|
|
|
|
void _cdecl wmain( int argc, WCHAR * argv[] )
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
BOOL b = TRUE;
|
|
DWORD DesiredAccess;
|
|
DWORD Callback;
|
|
DWORD Iteration;
|
|
|
|
AUTHZ_RESOURCE_MANAGER_HANDLE hRM = NULL;
|
|
HANDLE hToken = NULL;
|
|
LUID luid = {0xdead,0xbeef};
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hCC1 = NULL;
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hCC2 = NULL;
|
|
AUTHZ_CLIENT_CONTEXT_HANDLE hCC3 = NULL;
|
|
AUTHZ_ACCESS_REQUEST Request;
|
|
PAUTHZ_ACCESS_REPLY pReply = (PAUTHZ_ACCESS_REPLY) Buffer;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD dwErr;
|
|
ULONG i = 0, jj = 0;
|
|
PACE_HEADER Ace = NULL;
|
|
DWORD AceCount = 0;
|
|
DWORD Len = 0;
|
|
SID_AND_ATTRIBUTES SidAttr[1];
|
|
AUTHZ_AUDIT_INFO_HANDLE hAuditInfo = NULL;
|
|
AUTHZ_RM_AUDIT_INFO_HANDLE hRmAuditInfo;
|
|
PAUDIT_PARAMS pAuditParams;
|
|
|
|
AUTHZ_HANDLE AuthHandle = 0;
|
|
PACL pAcl = NULL;
|
|
AUDIT_EVENT_INFO AuditEventInfo;
|
|
PSID pUserSid = NULL;
|
|
AUTHZ_AUDIT_QUEUE_HANDLE hQueue;
|
|
|
|
PWCHAR StringSD = L"O:BAG:DUD:(A;;0x40;;;s-1-2-2)(A;;0x1;;;BA)(OA;;0x2;6da8a4ff-0e52-11d0-a286-00aa00304900;;BA)(OA;;0x4;6da8a4ff-0e52-11d0-a286-00aa00304901;;BA)(OA;;0x8;6da8a4ff-0e52-11d0-a286-00aa00304903;;AU)(OA;;0x10;6da8a4ff-0e52-11d0-a286-00aa00304904;;BU)(OA;;0x20;6da8a4ff-0e52-11d0-a286-00aa00304905;;AU)(A;;0x40;;;PS)S:(AU;IDSAFA;0xFFFFFF;;;WD)";
|
|
//PWCHAR StringSD = L"O:BAG:DUD:(A;;0x100;;;SY)(A;;0x100;;;PS)S:(AU;IDSA;SD;;;DU)";
|
|
|
|
if (argc != 4)
|
|
{
|
|
wprintf(L"usage: %s access iter [callback]\n", argv[0]);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
DesiredAccess = wcstol(argv[1], NULL, 16);
|
|
Iteration = wcstol(argv[2], NULL, 16);
|
|
Callback = wcstol(argv[3], NULL, 16);
|
|
|
|
//
|
|
// Create the SD for the access checks
|
|
//
|
|
|
|
b = ConvertStringSecurityDescriptorToSecurityDescriptorW(StringSD, SDDL_REVISION_1, &pSD, NULL);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"SDDL failed with %d\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If Callback aces are specified, change the DACL to use them
|
|
//
|
|
|
|
if (Callback)
|
|
{
|
|
pAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR) pSD);
|
|
AceCount = pAcl->AceCount;
|
|
|
|
for (i = 0, Ace = FirstAce(pAcl); i < AceCount; i++, Ace = NextAce(Ace))
|
|
{
|
|
switch(Ace->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
Ace->AceType = ACCESS_ALLOWED_CALLBACK_ACE_TYPE;
|
|
break;
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
Ace->AceType = ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
AuditEventInfo.Version = AUDIT_TYPE_LEGACY;
|
|
AuditEventInfo.u.Legacy.CategoryId = SE_CATEGID_OBJECT_ACCESS;
|
|
AuditEventInfo.u.Legacy.AuditId = SE_AUDITID_OBJECT_OPERATION;
|
|
AuditEventInfo.u.Legacy.ParameterCount = 11;
|
|
|
|
b = AuthzInitializeAuditQueue(
|
|
&hQueue,
|
|
0,
|
|
1000,
|
|
100,
|
|
NULL
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"authzinitauditqueueueueue %d\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
if (!b)
|
|
{
|
|
printf("AuthzAllocInitRmAuditInfoHandle FAILED.\n");
|
|
return;
|
|
}
|
|
|
|
b = AuthzInitializeResourceManager(
|
|
MyAccessCheck,
|
|
MyComputeDynamicGroups,
|
|
MyFreeDynamicGroups,
|
|
L"some rm",
|
|
0, // Flags
|
|
&hRM
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"AuthzInitializeResourceManager failed with %d\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// AuthzInitializeAuditParamsWithRM(
|
|
// &pAuditParams,
|
|
// hRM,
|
|
// APF_AuditSuccess,
|
|
// 1,
|
|
// APT_String, L"Jeff operation"
|
|
// );
|
|
//
|
|
//
|
|
b = AuthzInitializeAuditInfo(
|
|
&hAuditInfo,
|
|
0,
|
|
hRM,
|
|
&AuditEventInfo,
|
|
NULL,//pAuditParams,
|
|
hQueue,
|
|
INFINITE,
|
|
L"Cleaning",
|
|
L"Toothbrush",
|
|
L"Oral B",
|
|
L"Rinse after brushing."
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
printf("AuthzInitAuditInfo FAILED with %d.\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&hToken
|
|
);
|
|
|
|
b = AuthzInitializeContextFromToken(
|
|
hToken,
|
|
hRM,
|
|
NULL,
|
|
luid,
|
|
0,
|
|
NULL,
|
|
&hCC1
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"AuthzInitializeContextFromSid failed with 0x%x\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
Request.ObjectTypeList = (POBJECT_TYPE_LIST) TypeListBuffer;
|
|
Request.ObjectTypeList[0].Level = 0;
|
|
Request.ObjectTypeList[0].ObjectType = &Guid0;
|
|
Request.ObjectTypeList[0].Sbz = 0;
|
|
Request.ObjectTypeListLength = 1;
|
|
Request.OptionalArguments = NULL;
|
|
Request.PrincipalSelfSid = NULL;
|
|
Request.DesiredAccess = 0x100;
|
|
|
|
//
|
|
// The ResultListLength is set to the number of ObjectType GUIDs in the Request, indicating
|
|
// that the caller would like detailed information about granted access to each node in the
|
|
// tree.
|
|
//
|
|
RtlZeroMemory(Buffer, sizeof(Buffer));
|
|
pReply->ResultListLength = 1;
|
|
pReply->Error = (PDWORD) (((PCHAR) pReply) + sizeof(AUTHZ_ACCESS_REPLY));
|
|
pReply->GrantedAccessMask = (PACCESS_MASK) (pReply->Error + pReply->ResultListLength);
|
|
|
|
|
|
wprintf(L"* AccessCheck (PSS == NULL, ResultListLength == 1 with cache handle)\n");
|
|
b = AuthzAccessCheck(
|
|
hCC1,
|
|
&Request,
|
|
hAuditInfo,
|
|
pSD,
|
|
NULL,
|
|
0,
|
|
pReply,
|
|
&AuthHandle
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
AuthzFreeAuditInfo(hAuditInfo);
|
|
AuthzFreeAuditQueue(hQueue);
|
|
return;
|
|
|
|
RtlZeroMemory(Buffer, sizeof(Buffer));
|
|
pReply->ResultListLength = 1;
|
|
pReply->Error = (PDWORD) (((PCHAR) pReply) + sizeof(AUTHZ_ACCESS_REPLY));
|
|
pReply->GrantedAccessMask = (PACCESS_MASK) (pReply->Error + pReply->ResultListLength);
|
|
|
|
wprintf(L"* AccessCheck (PSS == NULL, ResultListLength == 1 without cache handle)\n");
|
|
b = AuthzAccessCheck(
|
|
hCC1,
|
|
&Request,
|
|
hAuditInfo,
|
|
pSD,
|
|
NULL,
|
|
0,
|
|
pReply,
|
|
NULL
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
AuthzFreeAuditParams(pAuditParams);
|
|
|
|
Request.ObjectTypeList = (POBJECT_TYPE_LIST) TypeListBuffer;
|
|
|
|
Request.ObjectTypeList[0].Level = 0;
|
|
Request.ObjectTypeList[0].ObjectType = &Guid0;
|
|
Request.ObjectTypeList[0].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[1].Level = 1;
|
|
Request.ObjectTypeList[1].ObjectType = &Guid1;
|
|
Request.ObjectTypeList[1].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[2].Level = 2;
|
|
Request.ObjectTypeList[2].ObjectType = &Guid2;
|
|
Request.ObjectTypeList[2].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[3].Level = 2;
|
|
Request.ObjectTypeList[3].ObjectType = &Guid3;
|
|
Request.ObjectTypeList[3].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[4].Level = 1;
|
|
Request.ObjectTypeList[4].ObjectType = &Guid4;
|
|
Request.ObjectTypeList[4].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[5].Level = 2;
|
|
Request.ObjectTypeList[5].ObjectType = &Guid5;
|
|
Request.ObjectTypeList[5].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[6].Level = 3;
|
|
Request.ObjectTypeList[6].ObjectType = &Guid6;
|
|
Request.ObjectTypeList[6].Sbz = 0;
|
|
|
|
Request.ObjectTypeList[7].Level = 2;
|
|
Request.ObjectTypeList[7].ObjectType = &Guid7;
|
|
Request.ObjectTypeList[7].Sbz = 0;
|
|
|
|
Request.ObjectTypeListLength = 8;
|
|
Request.OptionalArguments = NULL;
|
|
|
|
Request.PrincipalSelfSid = NULL;
|
|
Request.DesiredAccess = DesiredAccess;
|
|
|
|
//
|
|
// The ResultListLength is set to the number of ObjectType GUIDs in the Request, indicating
|
|
// that the caller would like detailed information about granted access to each node in the
|
|
// tree.
|
|
//
|
|
|
|
pReply->ResultListLength = 8;
|
|
pReply->Error = (PDWORD) (((PCHAR) pReply) + sizeof(AUTHZ_ACCESS_REPLY));
|
|
pReply->GrantedAccessMask = (PACCESS_MASK) (pReply->Error + pReply->ResultListLength);
|
|
|
|
wprintf(L"* AccessCheck (PrincipalSelfSid == NULL, ResultListLength == 8)\n");
|
|
b = AuthzAccessCheck(
|
|
hCC1,
|
|
&Request,
|
|
hAuditInfo,
|
|
pSD,
|
|
NULL,
|
|
0,
|
|
pReply,
|
|
&AuthHandle
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// In the original AuthzAccessCheck call, we passed in a handle to store caching information. Now we
|
|
// can use this handle to perform an AccessCheck on the same object.
|
|
//
|
|
|
|
if (AuthHandle)
|
|
{
|
|
wprintf(L"* Cached AccessCheck (PrincipalSelfSid == NULL, ResultListLength = 8)\n");
|
|
b = AuthzCachedAccessCheck(
|
|
AuthHandle,
|
|
&Request,
|
|
hAuditInfo,
|
|
pReply
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Since we will no longer use this caching handle, free it.
|
|
//
|
|
|
|
AuthzFreeHandle(AuthHandle);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"No CachedAccessCheck done since NULL = AuthHandle\n");
|
|
}
|
|
|
|
//
|
|
// We set the PrincipalSelfSid in the Request, and leave all other parameters the same.
|
|
//
|
|
|
|
Request.PrincipalSelfSid = (PSID) KedarSid;
|
|
|
|
wprintf(L"* AccessCheck (PrincipalSelfSid == Kedard, ResultListLength == 8)\n");
|
|
b = AuthzAccessCheck(
|
|
hCC1,
|
|
&Request,
|
|
hAuditInfo,
|
|
pSD,
|
|
NULL,
|
|
0,
|
|
pReply,
|
|
&AuthHandle
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Use our caching handle to perform the same AccessCheck with speed.
|
|
//
|
|
|
|
if (AuthHandle)
|
|
{
|
|
wprintf(L"* Cached AccessCheck (PrincipalSelfSid == Kedard, ResultListLength = 8)\n");
|
|
b = AuthzCachedAccessCheck(
|
|
AuthHandle,
|
|
&Request,
|
|
hAuditInfo,
|
|
pReply
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the handle, since it will not be used again.
|
|
//
|
|
|
|
AuthzFreeHandle(AuthHandle);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"No CachedAccessCheck done since NULL = AuthHandle\n");
|
|
}
|
|
|
|
|
|
//
|
|
// Set the ResultListLength to 1, indicating that we do not care about the results
|
|
// of the AccessCheck at the individual nodes in the tree. Rather, we care about
|
|
// our permissions to the entire tree. The returned access indicates if we have
|
|
// access to the whole thing.
|
|
//
|
|
|
|
pReply->ResultListLength = 1;
|
|
|
|
wprintf(L"* AccessCheck (PrincipalSelfSid == Kedard, ResultListLength == 1)\n");
|
|
b = AuthzAccessCheck(
|
|
hCC1,
|
|
&Request,
|
|
hAuditInfo,
|
|
pSD,
|
|
NULL,
|
|
0,
|
|
pReply,
|
|
NULL
|
|
);
|
|
|
|
if (!b)
|
|
{
|
|
wprintf(L"\tFailed. LastError = %d\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"\tSucceeded. Granted Access Masks:\n");
|
|
|
|
for (i = 0; i < pReply->ResultListLength; i++)
|
|
{
|
|
wprintf(L"\t\tObjectType %d :: AccessMask = 0x%x, Error = %d\n",
|
|
i, pReply->GrantedAccessMask[i], pReply->Error[i]);
|
|
}
|
|
}
|
|
|
|
// for (i = 0; i < 10; i ++)
|
|
// {
|
|
// AuthzOpenObjectAuditAlarm(
|
|
// hCC1,
|
|
// &Request,
|
|
// hAuditInfo,
|
|
// pSD,
|
|
// NULL,
|
|
// 0,
|
|
// pReply
|
|
// );
|
|
//
|
|
// if (!b)
|
|
// {
|
|
// wprintf(L"AuthzOpenObjectAuditAlarm failed with %d\n", GetLastError);
|
|
// }
|
|
// }
|
|
|
|
//
|
|
// Free the RM auditing data before exiting. This call is importants, as it also waits on
|
|
// threads used by the Authzs auditing component to complete.
|
|
//
|
|
|
|
//AuthzFreeRmAuditInfoHandle(hRmAuditInfo);
|
|
|
|
//
|
|
// Free the contexts that the RM created.
|
|
//
|
|
|
|
AuthzFreeContext(hCC1);
|
|
AuthzFreeAuditQueue(hQueue);
|
|
|
|
return;
|
|
}
|
|
|