Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1588 lines
47 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1996
//
// File: tcertpro.cpp
//
// Contents: Cert Protection Tests
//
// See Usage() for a list of test options.
//
//
// Functions: main
//
// History: 30-Nov-97 philh created
//--------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include "wincrypt.h"
#include "certtest.h"
#include "unicode.h"
#include "certprot.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
static void PrintLastError(LPCSTR pszMsg, LONG lErr)
{
printf(" %s failed => 0x%x (%d) \n", pszMsg, lErr, lErr);
}
static void PrintLastError(LPCSTR pszMsg)
{
DWORD dwErr = GetLastError();
printf(" %s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
}
static
BOOL
SetPrivilege(
HANDLE hToken, // token handle
LPCSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValueA( NULL, Privilege, &luid )) return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege) {
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
}
else {
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
}
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
return TRUE;
}
static
BOOL
SetCurrentPrivilege(
LPCSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
BOOL bSuccess=FALSE; // assume failure
HANDLE hToken;
if(OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken
))
{
if(SetPrivilege(hToken, Privilege, bEnablePrivilege)) bSuccess=TRUE;
CloseHandle(hToken);
}
return bSuccess;
}
static void Usage(void)
{
printf("Usage: tcertpro [options] <TestName> <RegPath>\n");
printf("Options are:\n");
printf(" -h - This message\n");
// printf(" -r - Recurse subkeys\n");
printf(" -lCU - CurrentUser (default)\n");
printf(" -lLM - LocalMachine\n");
printf("TestNames (case insensitive):\n");
printf(" GetKey - Get Registry Key Security Information\n");
printf(" SetKey - Set Registry Key Security Information\n");
printf(" PurgeLMRoots - Purge LocalMachine Roots From CurrentUser\n");
printf(" DeleteUnknownRoots - Delete Unknown Roots From Protected List\n");
printf(" CheckProtectedRoots - Check ProtectedRoots ACLs\n");
printf(" ServiceUI - Cert protect service UI\n");
printf(" ServiceTokenInfo - Get Cert protect service token info\n");
printf(" ServiceInvalid - Invalid Cert protect function\n");
printf("\n");
}
#if 0
#define OWNER_SECURITY_INFORMATION (0X00000001L)
#define GROUP_SECURITY_INFORMATION (0X00000002L)
#define DACL_SECURITY_INFORMATION (0X00000004L)
#define SACL_SECURITY_INFORMATION (0X00000008L)
#endif
static PSECURITY_DESCRIPTOR AllocAndGetSecurityDescriptor(
IN HKEY hKey,
SECURITY_INFORMATION SecInf
)
{
LONG err;
PSECURITY_DESCRIPTOR psd = NULL;
DWORD cbsd = 0;
err = RegGetKeySecurity(
hKey,
SecInf,
NULL, // psd
&cbsd
);
if (!(ERROR_SUCCESS == err || ERROR_INSUFFICIENT_BUFFER == err)) {
PrintLastError("RegGetKeySecurity", err);
return NULL;
}
if (0 == cbsd)
return NULL;
if (NULL == (psd = (PSECURITY_DESCRIPTOR) TestAlloc(cbsd)))
return NULL;
if (ERROR_SUCCESS != (err = RegGetKeySecurity(
hKey,
SecInf,
psd,
&cbsd
))) {
PrintLastError("RegGetKeySecurity", err);
TestFree(psd);
}
return psd;
}
#if 0
#define SE_OWNER_DEFAULTED (0x0001)
#define SE_GROUP_DEFAULTED (0x0002)
#define SE_DACL_PRESENT (0x0004)
#define SE_DACL_DEFAULTED (0x0008)
#define SE_SACL_PRESENT (0x0010)
#define SE_SACL_DEFAULTED (0x0020)
#define SE_DACL_AUTO_INHERIT_REQ (0x0100)
#define SE_SACL_AUTO_INHERIT_REQ (0x0200)
#define SE_DACL_AUTO_INHERITED (0x0400)
#define SE_SACL_AUTO_INHERITED (0x0800)
#define SE_DACL_PROTECTED (0x1000)
#define SE_SACL_PROTECTED (0x2000)
#define SE_SELF_RELATIVE (0x8000)
#endif
//
// Where:
//
// SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the
// SID pointed to by the Owner field was provided by a
// defaulting mechanism rather than explicitly provided by the
// original provider of the security descriptor. This may
// affect the treatment of the SID with respect to inheritence
// of an owner.
//
// SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the
// SID in the Group field was provided by a defaulting mechanism
// rather than explicitly provided by the original provider of
// the security descriptor. This may affect the treatment of
// the SID with respect to inheritence of a primary group.
//
// SE_DACL_PRESENT - This boolean flag, when set, indicates that the
// security descriptor contains a discretionary ACL. If this
// flag is set and the Dacl field of the SECURITY_DESCRIPTOR is
// null, then a null ACL is explicitly being specified.
//
// SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the
// ACL pointed to by the Dacl field was provided by a defaulting
// mechanism rather than explicitly provided by the original
// provider of the security descriptor. This may affect the
// treatment of the ACL with respect to inheritence of an ACL.
// This flag is ignored if the DaclPresent flag is not set.
//
// SE_SACL_PRESENT - This boolean flag, when set, indicates that the
// security descriptor contains a system ACL pointed to by the
// Sacl field. If this flag is set and the Sacl field of the
// SECURITY_DESCRIPTOR is null, then an empty (but present)
// ACL is being specified.
//
// SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the
// ACL pointed to by the Sacl field was provided by a defaulting
// mechanism rather than explicitly provided by the original
// provider of the security descriptor. This may affect the
// treatment of the ACL with respect to inheritence of an ACL.
// This flag is ignored if the SaclPresent flag is not set.
//
// SE_SELF_RELATIVE - This boolean flag, when set, indicates that the
// security descriptor is in self-relative form. In this form,
// all fields of the security descriptor are contiguous in memory
// and all pointer fields are expressed as offsets from the
// beginning of the security descriptor. This form is useful
// for treating security descriptors as opaque data structures
// for transmission in communication protocol or for storage on
// secondary media.
//
#if 0
typedef enum _SID_NAME_USE {
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown
} SID_NAME_USE, *PSID_NAME_USE;
#endif
static void DisplayControl(
PSECURITY_DESCRIPTOR psd
)
{
SECURITY_DESCRIPTOR_CONTROL sdc;
DWORD dwRevision;
if (!GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
PrintLastError("GetSecurityDescriptorControl");
else {
printf(" Control: 0x%x", sdc);
if (sdc & SE_OWNER_DEFAULTED)
printf(" OWNER_DEFAULTED");
if (sdc & SE_GROUP_DEFAULTED)
printf(" GROUP_DEFAULTED");
if (sdc & SE_DACL_PRESENT)
printf(" DACL_PRESENT");
if (sdc & SE_DACL_DEFAULTED)
printf(" DACL_DEFAULTED");
if (sdc & SE_SACL_PRESENT)
printf(" SACL_PRESENT");
if (sdc & SE_SACL_DEFAULTED)
printf(" SACL_DEFAULTED");
if (sdc & SE_DACL_AUTO_INHERIT_REQ)
printf(" DACL_AUTO_INHERIT_REQ");
if (sdc & SE_SACL_AUTO_INHERIT_REQ)
printf(" SACL_AUTO_INHERIT_REQ");
if (sdc & SE_DACL_AUTO_INHERITED)
printf(" DACL_AUTO_INHERITED");
if (sdc & SE_SACL_AUTO_INHERITED)
printf(" SACL_AUTO_INHERITED");
if (sdc & SE_DACL_PROTECTED)
printf(" DACL_PROTECTED");
if (sdc & SE_SACL_PROTECTED)
printf(" SACL_PROTECTED");
if (sdc & SE_SELF_RELATIVE)
printf(" SELF_RELATIVE");
printf("\n");
printf(" Revision: %d\n", dwRevision);
}
}
static void DisplaySid(
PSID pSid
)
{
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwCounter;
char szAccount[_MAX_PATH];
DWORD cchAccount;
char szDomain[_MAX_PATH];
DWORD cchDomain;
SID_NAME_USE snu;
if (!IsValidSid(pSid)) {
printf("Invalid SID\n");
return;
}
// obtain SidIdentifierAuthority
psia = GetSidIdentifierAuthority(pSid);
// obtain sidsubauthority count
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
//
// prepare S-SID_REVISION-
//
printf("S-%lu-", SID_REVISION);
//
// prepare SidIdentifierAuthority
//
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) {
printf("0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
} else {
printf("%lu",
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
}
//
// loop through SidSubAuthorities
//
for (dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++) {
printf("-%lu", *GetSidSubAuthority(pSid, dwCounter) );
}
cchAccount = sizeof(szAccount) - 1;
memset(szAccount, 0, sizeof(szAccount));
cchDomain = sizeof(szDomain) - 1;
memset(szDomain, 0, sizeof(szDomain));
snu = (SID_NAME_USE) 0;
if (LookupAccountSidA(
NULL, // lpSystemName
pSid,
szAccount,
&cchAccount,
szDomain,
&cchDomain,
&snu
))
printf(" Account: %s Domain: %s SNU: %d", szAccount, szDomain, snu);
printf("\n");
}
static void DisplayOwnerSecurityInfo(
IN PSECURITY_DESCRIPTOR psd
)
{
PSID pSid = NULL;
BOOL fOwnerDefaulted;
if (!GetSecurityDescriptorOwner(psd, &pSid, &fOwnerDefaulted)) {
PrintLastError("GetSecurityDescriptorOwner");
return;
}
if (NULL == pSid)
printf(" NO OWNER\n");
else {
printf(" Owner: ");
DisplaySid(pSid);
if (fOwnerDefaulted)
printf(" Owner Defaulted\n");
}
}
static void DisplayGroupSecurityInfo(
IN PSECURITY_DESCRIPTOR psd
)
{
PSID pSid = NULL;
BOOL fGroupDefaulted;
if (!GetSecurityDescriptorGroup(psd, &pSid, &fGroupDefaulted)) {
PrintLastError("GetSecurityDescriptorGroup");
return;
}
if (NULL == pSid)
printf(" NO Group\n");
else {
printf(" Group: ");
DisplaySid(pSid);
if (fGroupDefaulted)
printf(" Group Defaulted\n");
}
}
static LPCSTR GetAceTypeString(
IN BYTE AceType
)
{
switch (AceType) {
case ACCESS_ALLOWED_ACE_TYPE:
return "ACCESS_ALLOWED";
break;
case ACCESS_DENIED_ACE_TYPE:
return "ACCESS_DENIED_ACE_TYPE";
break;
case SYSTEM_AUDIT_ACE_TYPE:
return "SYSTEM_AUDIT_ACE_TYPE";
break;
case SYSTEM_ALARM_ACE_TYPE:
return "SYSTEM_ALARM_ACE_TYPE";
break;
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
return "ACCESS_ALLOWED_COMPOUND_ACE_TYPE";
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
return "ACCESS_ALLOWED_OBJECT_ACE_TYPE";
break;
case ACCESS_DENIED_OBJECT_ACE_TYPE:
return "ACCESS_DENIED_OBJECT_ACE_TYPE";
break;
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
return "SYSTEM_AUDIT_OBJECT_ACE_TYPE";
break;
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
return "SYSTEM_ALARM_OBJECT_ACE_TYPE";
break;
default:
return "???";
}
}
static void DisplayAceFlags(
IN BYTE AceFlags
)
{
if (AceFlags & OBJECT_INHERIT_ACE)
printf(" OBJECT_INHERIT");
if (AceFlags & CONTAINER_INHERIT_ACE)
printf(" CONTAINER_INHERIT");
if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
printf(" NO_PROPAGATE_INHERIT");
if (AceFlags & INHERIT_ONLY_ACE)
printf(" INHERIT_ONLY");
if (AceFlags & INHERITED_ACE)
printf(" INHERITED");
if (AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
printf(" SUCCESSFUL_ACCESS");
if (AceFlags & FAILED_ACCESS_ACE_FLAG)
printf(" FAILED_ACCESS");
}
static void DisplayAccessMask(
IN ACCESS_MASK Mask
)
{
if (Mask & SYNCHRONIZE)
printf(" SYNCHRONIZE");
if (Mask & ACCESS_SYSTEM_SECURITY)
printf(" ACCESS_SYSTEM_SECURITY");
if (Mask & MAXIMUM_ALLOWED)
printf(" MAXIMUM_ALLOWED");
if (Mask & GENERIC_READ)
printf(" GENERIC_READ");
if (Mask & GENERIC_WRITE)
printf(" GENERIC_WRITE");
if (Mask & GENERIC_EXECUTE)
printf(" GENERIC_EXECUTE");
if (Mask & GENERIC_ALL)
printf(" GENERIC_ALL");
if (KEY_ALL_ACCESS == (Mask & KEY_ALL_ACCESS)) {
printf(" KEY_ALL_ACCESS");
return;
}
if (KEY_READ == (Mask & KEY_READ))
printf(" KEY_READ");
if (KEY_WRITE == (Mask & KEY_WRITE))
printf(" KEY_WRITE");
if (KEY_EXECUTE == (Mask & KEY_EXECUTE))
printf(" KEY_EXECUTE");
if (Mask & DELETE)
printf(" DELETE");
if (Mask & READ_CONTROL)
printf(" READ_CONTROL");
if (Mask & WRITE_DAC)
printf(" WRITE_DAC");
if (Mask & WRITE_OWNER)
printf(" WRITE_OWNER");
if (Mask & KEY_QUERY_VALUE)
printf(" KEY_QUERY_VALUE");
if (Mask & KEY_SET_VALUE)
printf(" KEY_SET_VALUE");
if (Mask & KEY_CREATE_SUB_KEY)
printf(" KEY_CREATE_SUB_KEY");
if (Mask & KEY_ENUMERATE_SUB_KEYS)
printf(" KEY_ENUMERATE_SUB_KEYS");
if (Mask & KEY_NOTIFY)
printf(" KEY_NOTIFY");
if (Mask & KEY_CREATE_LINK)
printf(" KEY_CREATE_LINK");
}
static void DisplayAcl(
IN BOOL fDaclPresent,
IN PACL pAcl,
IN BOOL fDaclDefaulted
)
{
DWORD dwAceIndex;
if (!fDaclPresent) {
printf(" NO ACL\n");
return;
}
if (NULL == pAcl) {
printf(" NULL ACL\n");
return;
}
printf(" AclRevision: %d", pAcl->AclRevision);
if (fDaclDefaulted)
printf(" Defaulted ACL");
printf("\n");
for (dwAceIndex = 0; dwAceIndex < pAcl->AceCount; dwAceIndex++) {
PACE_HEADER pAceHdr;
PACCESS_ALLOWED_ACE pAce;
if (!GetAce(pAcl, dwAceIndex, (void **) &pAceHdr)) {
PrintLastError("GetAce");
return;
}
printf(" Ace[%d]\n", dwAceIndex);
printf(" Type: 0x%x %s\n", pAceHdr->AceType,
GetAceTypeString(pAceHdr->AceType));
printf(" Flags: 0x%x ", pAceHdr->AceFlags);
DisplayAceFlags(pAceHdr->AceFlags);
printf("\n");
switch (pAceHdr->AceType) {
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
pAce = (PACCESS_ALLOWED_ACE) pAceHdr;
printf(" Mask: 0x%x", pAce->Mask);
DisplayAccessMask(pAce->Mask);
printf("\n");
printf(" SID: ");
DisplaySid((PSID) &pAce->SidStart);
break;
default:
break;
}
}
}
static void DisplayDaclSecurityInfo(
IN PSECURITY_DESCRIPTOR psd
)
{
BOOL fDaclPresent;
PACL pAcl;
BOOL fDaclDefaulted;
DWORD dwAceIndex;
printf(" --- DACLs ---\n");
if (!GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAcl,
&fDaclDefaulted)) {
PrintLastError("GetSecurityDescriptorDacl");
return;
}
DisplayAcl(fDaclPresent, pAcl, fDaclDefaulted);
}
static void DisplaySaclSecurityInfo(
IN PSECURITY_DESCRIPTOR psd
)
{
BOOL fSaclPresent;
PACL pAcl;
BOOL fSaclDefaulted;
DWORD dwAceIndex;
printf(" --- SACLs ---\n");
if (!GetSecurityDescriptorSacl(psd, &fSaclPresent, &pAcl,
&fSaclDefaulted)) {
PrintLastError("GetSecurityDescriptorSacl");
return;
}
DisplayAcl(fSaclPresent, pAcl, fSaclDefaulted);
}
static void DisplayRegQueryInfo(
IN HKEY hKey
)
{
FILETIME ftLastWriteTime;
LONG err;
memset(&ftLastWriteTime, 0, sizeof(ftLastWriteTime));
if (ERROR_SUCCESS == (err = RegQueryInfoKeyA(
hKey,
NULL, // lpszClass
NULL, // lpcchClass
NULL, // lpdwReserved
NULL, // lpcSubKeys
NULL, // lpcchMaxSubKey
NULL, // lpcchMaxClass
NULL, // lpcValues
NULL, // lpcchMaxValuesName
NULL, // lpcbMaxValueData
NULL, // lpcbSecurityDescriptor
&ftLastWriteTime
))) {
printf("LastWriteTime:: %s\n", FileTimeText(&ftLastWriteTime));
}
}
static void DisplayRegSecurityInfo(
IN HKEY hKey,
IN LPCSTR pszKeyBase,
IN LPCSTR pszRegPath,
SECURITY_INFORMATION SecInf,
IN BOOL fRecurse
)
{
PSECURITY_DESCRIPTOR psd = NULL;
printf("%s\\%s\n", pszKeyBase, pszRegPath);
if (NULL == (psd = AllocAndGetSecurityDescriptor(
hKey, SecInf)))
return;
DisplayRegQueryInfo(hKey);
DisplayControl(psd);
DisplayOwnerSecurityInfo(psd);
DisplayGroupSecurityInfo(psd);
DisplayDaclSecurityInfo(psd);
if (SecInf & SACL_SECURITY_INFORMATION)
DisplaySaclSecurityInfo(psd);
TestFree(psd);
if (fRecurse) {
}
}
static void * AllocAndGetTokenInfo(
IN HANDLE hToken,
IN TOKEN_INFORMATION_CLASS tic
)
{
void *pvInfo = NULL;
DWORD cbInfo = 0;
DWORD cbInfo2;
if (!GetTokenInformation(
hToken,
tic,
pvInfo,
0, // cbInfo
&cbInfo
)) {
if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
PrintLastError("GetTokenInformation");
return NULL;
}
}
if (0 == cbInfo) {
printf("No Information\n");
return NULL;
}
if (NULL == (pvInfo = TestAlloc(cbInfo)))
return NULL;
cbInfo2 = cbInfo;
if (!GetTokenInformation(
hToken,
tic,
pvInfo,
cbInfo,
&cbInfo2
)) {
PrintLastError("GetTokenInformation");
TestFree(pvInfo);
return NULL;
}
return pvInfo;
}
static void GetProcessTokenInfo()
{
HANDLE hToken = NULL;
void *pvInfo = NULL;
printf("Get Process Token Information\n\n");
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&hToken
)) {
PrintLastError("OpenProcessToken");
goto ErrorReturn;
}
printf("TokenUser: ");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenUser)) {
PTOKEN_USER pTokenUser = (PTOKEN_USER) pvInfo;
if (pTokenUser->User.Attributes)
printf("Attributes(0x%x) ", pTokenUser->User.Attributes);
DisplaySid(pTokenUser->User.Sid);
TestFree(pvInfo);
pvInfo = NULL;
}
printf("TokenOwner: ");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenOwner)) {
PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) pvInfo;
DisplaySid(pTokenOwner->Owner);
TestFree(pvInfo);
pvInfo = NULL;
}
printf("TokenPrimaryGroup: ");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenPrimaryGroup)) {
PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup = (PTOKEN_PRIMARY_GROUP) pvInfo;
DisplaySid(pTokenPrimaryGroup->PrimaryGroup);
TestFree(pvInfo);
pvInfo = NULL;
}
printf("TokenGroups\n");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenGroups)) {
PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) pvInfo;
DWORD GroupCount = pTokenGroups->GroupCount;
if (0 == GroupCount)
printf(" No Groups\n");
else {
DWORD i;
for (i = 0; i < GroupCount; i++) {
printf(" Group[%d]: ", i);
if (pTokenGroups->Groups[i].Attributes)
printf("Attributes(0x%x) ",
pTokenGroups->Groups[i].Attributes);
DisplaySid(pTokenGroups->Groups[i].Sid);
}
}
TestFree(pvInfo);
pvInfo = NULL;
}
printf("TokenPrivileges\n");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenPrivileges)) {
PTOKEN_PRIVILEGES pTokenPrivileges = (PTOKEN_PRIVILEGES) pvInfo;
DWORD PrivilegeCount = pTokenPrivileges->PrivilegeCount;
if (0 == PrivilegeCount)
printf(" No Privileges\n");
else {
DWORD i;
for (i = 0; i < PrivilegeCount; i++) {
char szName[_MAX_PATH];
DWORD cchName;
printf(" Privilege[%d]: ", i);
if (pTokenPrivileges->Privileges[i].Attributes)
printf("Attributes(0x%x) ",
pTokenPrivileges->Privileges[i].Attributes);
cchName = sizeof(szName);
if (LookupPrivilegeName(
NULL, // pszSystemName
&pTokenPrivileges->Privileges[i].Luid,
szName,
&cchName
))
printf("%s\n", szName);
else
PrintLastError("LookupPrivlegeName");
}
}
TestFree(pvInfo);
pvInfo = NULL;
}
printf("TokenDefaultDacl\n");
if (pvInfo = AllocAndGetTokenInfo(hToken, TokenDefaultDacl)) {
PTOKEN_DEFAULT_DACL pTokenDacl = (PTOKEN_DEFAULT_DACL) pvInfo;
DisplayAcl(TRUE, pTokenDacl->DefaultDacl, FALSE);
TestFree(pvInfo);
pvInfo = NULL;
}
ErrorReturn:
if (hToken)
CloseHandle(hToken);
TestFree(pvInfo);
}
static void SetOwner(
IN HKEY hKeyBase,
IN LPCSTR pszRegPath
)
{
LONG err;
HKEY hKey = NULL;
HANDLE hToken = NULL;
void *pvInfo = NULL;
SECURITY_DESCRIPTOR sd;
PSID pSid; // not allocated
printf("SetOwner\n");
if (!SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE))
PrintLastError("SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME)");
if (ERROR_SUCCESS != (err = RegOpenKeyExA(
hKeyBase,
pszRegPath,
0, // dwReserved
WRITE_OWNER,
&hKey))) {
if (ERROR_FILE_NOT_FOUND == err) {
DWORD dwDisposition;
if (ERROR_SUCCESS == (err = RegCreateKeyExA(
hKeyBase,
pszRegPath,
0, // dwReserved
NULL, // lpClass
REG_OPTION_NON_VOLATILE,
WRITE_OWNER,
NULL, // lpSecurityAttributes
&hKey,
&dwDisposition)))
printf("Created Subkey\n");
}
}
if (ERROR_SUCCESS != err) {
PrintLastError("RegOpenKeyExA(WRITE_OWNER)", err);
hKey = NULL;
goto ErrorReturn;
}
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
PrintLastError("InitializeSecurityDescriptor");
goto ErrorReturn;
}
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&hToken
)) {
PrintLastError("OpenProcessToken");
goto ErrorReturn;
}
if (NULL == (pvInfo = AllocAndGetTokenInfo(hToken, TokenUser)))
goto ErrorReturn;
else {
PTOKEN_USER pTokenUser = (PTOKEN_USER) pvInfo;
pSid = pTokenUser->User.Sid;
}
if (!SetSecurityDescriptorOwner(&sd, pSid, FALSE)) {
PrintLastError("SetSecurityDescriptorOwner");
goto ErrorReturn;
}
if (ERROR_SUCCESS != (err = RegSetKeySecurity(
hKey,
OWNER_SECURITY_INFORMATION,
&sd
))) {
PrintLastError("RegSetKeySecurity(OWNER)", err);
goto ErrorReturn;
}
ErrorReturn:
if (hKey)
RegCloseKey(hKey);
if (hToken)
CloseHandle(hToken);
TestFree(pvInfo);
}
static void SetGroupDaclSacl(
IN HKEY hKeyBase,
IN LPCSTR pszRegPath
)
{
LONG err;
HKEY hKey = NULL;
HANDLE hToken = NULL;
void *pvGroupInfo = NULL;
void *pvUserInfo = NULL;
SECURITY_DESCRIPTOR sd;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority =
SECURITY_WORLD_SID_AUTHORITY;
PSID psidLocalSystem = NULL;
PSID psidAdministrators = NULL;
PSID psidEveryone = NULL;
PSID psidUser; // Not allocated
PACL pDacl = NULL;
PACCESS_ALLOWED_ACE pAce;
DWORD dwAclSize;
DWORD i;
SECURITY_INFORMATION SecInf = DACL_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION;
REGSAM samDesired = WRITE_OWNER | WRITE_DAC;
printf("SetGroupDaclSacl\n");
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
PrintLastError("InitializeSecurityDescriptor");
goto ErrorReturn;
}
if (!SetCurrentPrivilege(SE_SECURITY_NAME, TRUE))
PrintLastError("SetCurrentPrivilege(SE_SECURITY_NAME)");
else {
SecInf |= SACL_SECURITY_INFORMATION;
samDesired |= ACCESS_SYSTEM_SECURITY;
if (!SetSecurityDescriptorSacl(&sd, FALSE, NULL, FALSE)) {
PrintLastError("SetSecurityDescriptorSacl");
goto ErrorReturn;
}
}
if (ERROR_SUCCESS != (err = RegOpenKeyExA(
hKeyBase,
pszRegPath,
0, // dwReserved
samDesired,
&hKey))) {
PrintLastError("RegOpenKeyExA(WRITE_OWNER | WRITE_DAC)", err);
hKey = NULL;
goto ErrorReturn;
}
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&hToken
)) {
PrintLastError("OpenProcessToken");
goto ErrorReturn;
}
if (NULL == (pvGroupInfo = AllocAndGetTokenInfo(hToken, TokenPrimaryGroup)))
goto ErrorReturn;
else {
PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup =
(PTOKEN_PRIMARY_GROUP) pvGroupInfo;
PSID pSid = pTokenPrimaryGroup->PrimaryGroup;
if (!SetSecurityDescriptorGroup(&sd, pSid, FALSE)) {
PrintLastError("SetSecurityDescriptorGroup");
goto ErrorReturn;
}
}
if (NULL == (pvUserInfo = AllocAndGetTokenInfo(hToken, TokenUser)))
goto ErrorReturn;
else {
PTOKEN_USER pTokenUser = (PTOKEN_USER) pvUserInfo;
psidUser = pTokenUser->User.Sid;
}
//
// prepare the SIDS for LocalSystem, Administrators and Everyone
//
if (!AllocateAndInitializeSid(
&siaNtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&psidLocalSystem
)) {
PrintLastError("AllocateAndInitializeSid(LocalSystem)");
goto ErrorReturn;
}
if (!AllocateAndInitializeSid(
&siaNtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators
)) {
PrintLastError("AllocateAndInitializeSid(Administrators)");
goto ErrorReturn;
}
if (!AllocateAndInitializeSid(
&siaWorldSidAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&psidEveryone
)) {
PrintLastError("AllocateAndInitializeSid(Everyone)");
goto ErrorReturn;
}
//
// compute size of new acl
//
dwAclSize = sizeof(ACL) +
4 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
GetLengthSid(psidLocalSystem) +
GetLengthSid(psidAdministrators) +
GetLengthSid(psidEveryone) +
GetLengthSid(psidUser)
;
//
// allocate storage for Acl
//
if (NULL == (pDacl = (PACL) TestAlloc(dwAclSize)))
goto ErrorReturn;
if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION)) {
PrintLastError("InitializeAcl");
goto ErrorReturn;
}
if (!AddAccessAllowedAce(
pDacl,
ACL_REVISION,
KEY_ALL_ACCESS,
psidLocalSystem
)) {
PrintLastError("AddAccessAllowedAce(LocalSystem)");
goto ErrorReturn;
}
if (!AddAccessAllowedAce(
pDacl,
ACL_REVISION,
KEY_ALL_ACCESS,
psidAdministrators
)) {
PrintLastError("AddAccessAllowedAce(Administrators)");
goto ErrorReturn;
}
if (!AddAccessAllowedAce(
pDacl,
ACL_REVISION,
KEY_READ,
psidEveryone
)) {
PrintLastError("AddAccessAllowedAce(Everyone)");
goto ErrorReturn;
}
if (!AddAccessAllowedAce(
pDacl,
ACL_REVISION,
KEY_ALL_ACCESS,
psidUser
)) {
PrintLastError("AddAccessAllowedAce(User)");
goto ErrorReturn;
}
//
// make containers inherit.
//
for (i = 0; i < 4; i++) {
if(!GetAce(pDacl, i, (void **) &pAce)) {
PrintLastError("GetAce");
goto ErrorReturn;
}
pAce->Header.AceFlags = CONTAINER_INHERIT_ACE;
}
if (!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE)) {
PrintLastError("SetSecurityDescriptorDacl");
goto ErrorReturn;
}
if (ERROR_SUCCESS != (err = RegSetKeySecurity(
hKey,
SecInf,
&sd
))) {
PrintLastError("RegSetKeySecurity(Group, DACL, SACL)", err);
goto ErrorReturn;
}
ErrorReturn:
if (hKey)
RegCloseKey(hKey);
if (hToken)
CloseHandle(hToken);
TestFree(pvGroupInfo);
TestFree(pvUserInfo);
if (psidLocalSystem)
FreeSid(psidLocalSystem);
if (psidAdministrators)
FreeSid(psidAdministrators);
if (psidEveryone)
FreeSid(psidEveryone);
TestFree(pDacl);
}
#define PROT_ROOT_SUBKEY_NAME L"ProtectedRoots"
#define SYSTEM_STORE_REGPATH L"Software\\Microsoft\\SystemCertificates"
#define PROT_ROOT_REGPATH \
SYSTEM_STORE_REGPATH L"\\Root\\" PROT_ROOT_SUBKEY_NAME
#define PSID_PROT_OWNER psidAdministrators
#define PSID_PROT_SYSTEM psidLocalSystem
#define PSID_PROT_EVERYONE psidEveryone
//+-------------------------------------------------------------------------
// ACL definitions used to set security on the "ProtectedRoots" SubKey.
//--------------------------------------------------------------------------
#define PROT_SYSTEM_ACE_MASK KEY_ALL_ACCESS
#define PROT_EVERYONE_ACE_MASK KEY_READ
#define PROT_ACE_FLAGS CONTAINER_INHERIT_ACE
#define PROT_ACE_COUNT 2
#define PROT_SYSTEM_ACE_INDEX 0
#define PROT_EVERYONE_ACE_INDEX 1
static void CheckProtectedRoots()
{
LONG lErr;
HKEY hKeyProtRoot = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
PSID psidOwner; // not allocated
BOOL fOwnerDefaulted;
BOOL fDaclPresent;
PACL pAcl; // not allocated
BOOL fDaclDefaulted;
DWORD dwAceIndex;
PACCESS_ALLOWED_ACE rgpAce[PROT_ACE_COUNT];
PSID psidLocalSystem = NULL;
PSID psidAdministrators = NULL;
PSID psidEveryone = NULL;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority =
SECURITY_WORLD_SID_AUTHORITY;
if (ERROR_SUCCESS != (lErr = RegOpenKeyExU(
HKEY_CURRENT_USER,
PROT_ROOT_REGPATH,
0, // dwReserved
KEY_READ,
&hKeyProtRoot))) {
PrintLastError("OpenProtectedRootKey", lErr);
goto ErrorReturn;
}
if (NULL == (psd = AllocAndGetSecurityDescriptor(
hKeyProtRoot,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
)))
goto ErrorReturn;
//
// prepare the SIDS for LocalSystem, Administrators and Everyone
//
if (!AllocateAndInitializeSid(
&siaNtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&psidLocalSystem
)) {
PrintLastError("AllocateAndInitializeSid(LocalSystem)");
goto ErrorReturn;
}
if (!AllocateAndInitializeSid(
&siaNtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators
)) {
PrintLastError("AllocateAndInitializeSid(Administrators)");
goto ErrorReturn;
}
if (!AllocateAndInitializeSid(
&siaWorldSidAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&psidEveryone
)) {
PrintLastError("AllocateAndInitializeSid(Everyone)");
goto ErrorReturn;
}
// Verify owner
if (!GetSecurityDescriptorOwner(psd, &psidOwner, &fOwnerDefaulted)) {
PrintLastError("GetSecurityDescriptorOwner");
goto ErrorReturn;
}
if (NULL == psidOwner || !EqualSid(psidOwner, PSID_PROT_OWNER)) {
printf("failed => invalid Owner\n");
goto ErrorReturn;
}
// Verify DACL
if (!GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAcl,
&fDaclDefaulted)) {
PrintLastError("GetSecurityDescriptorDacl");
goto ErrorReturn;
}
if (!fDaclPresent || NULL == pAcl) {
printf("failed => missing Dacl\n");
goto ErrorReturn;
}
if (PROT_ACE_COUNT != pAcl->AceCount) {
printf("failed => invalid AceCount\n");
goto ErrorReturn;
}
for (dwAceIndex = 0; dwAceIndex < PROT_ACE_COUNT; dwAceIndex++) {
PACCESS_ALLOWED_ACE pAce;
if (!GetAce(pAcl, dwAceIndex, (void **) &pAce)) {
printf("failed => invalid Acl\n");
goto ErrorReturn;
}
rgpAce[dwAceIndex] = pAce;
if (ACCESS_ALLOWED_ACE_TYPE != pAce->Header.AceType ||
PROT_ACE_FLAGS != pAce->Header.AceFlags) {
printf("failed => invalid Acl\n");
goto ErrorReturn;
}
}
if (PROT_SYSTEM_ACE_MASK != rgpAce[PROT_SYSTEM_ACE_INDEX]->Mask ||
!EqualSid(PSID_PROT_SYSTEM,
(PSID) &rgpAce[PROT_SYSTEM_ACE_INDEX]->SidStart) ||
PROT_EVERYONE_ACE_MASK != rgpAce[PROT_EVERYONE_ACE_INDEX]->Mask ||
!EqualSid(PSID_PROT_EVERYONE,
(PSID) &rgpAce[PROT_EVERYONE_ACE_INDEX]->SidStart)) {
printf("failed => invalid Acl\n");
goto ErrorReturn;
}
printf("Success => ProtectedRoots has correct ACLs\n");
CommonReturn:
if (psidLocalSystem)
FreeSid(psidLocalSystem);
if (psidAdministrators)
FreeSid(psidAdministrators);
if (psidEveryone)
FreeSid(psidEveryone);
TestFree(psd);
if (hKeyProtRoot)
RegCloseKey(hKeyProtRoot);
return;
ErrorReturn:
printf("Failed => ProtectedRoots has the following BAD ACLs\n");
if (hKeyProtRoot)
DisplayRegQueryInfo(hKeyProtRoot);
if (psd) {
DisplayControl(psd);
DisplayOwnerSecurityInfo(psd);
DisplayGroupSecurityInfo(psd);
DisplayDaclSecurityInfo(psd);
}
goto CommonReturn;
}
int _cdecl main(int argc, char * argv[])
{
int status;
#define TEST_NAME_INDEX 0
#define PATH_NAME_INDEX 1
#define MAX_NAME_CNT 2
DWORD dwNameCnt = 0;
LPCSTR rgpszName[MAX_NAME_CNT];
LPCSTR pszTestName; // not allocated
LPCSTR pszRegPath; // not allocated
HKEY hKeyBase = HKEY_CURRENT_USER;
LPCSTR pszKeyBase = "HKEY_CURRENT_USER";
BOOL fRecurse = FALSE;
HKEY hKey = NULL;
while (--argc>0) {
if (**++argv == '-')
{
switch(argv[0][1])
{
case 'l':
if (argv[0][2]) {
if (0 == _stricmp(argv[0]+2, "CU")) {
hKeyBase = HKEY_CURRENT_USER;
pszKeyBase = "HKEY_CURRENT_USER";
} else if (0 == _stricmp(argv[0]+2, "LM")) {
hKeyBase = HKEY_LOCAL_MACHINE;
pszKeyBase = "HKEY_LOCAL_MACHINE";
} else {
printf("Need to specify -lCU or -lLM\n");
goto BadUsage;
}
} else {
printf("Need to specify -lCU or -lLM\n");
goto BadUsage;
}
break;
case 'r':
fRecurse = TRUE;
break;
case 'h':
default:
goto BadUsage;
}
} else {
if (MAX_NAME_CNT <= dwNameCnt) {
printf("Too many names starting with:: %s\n", argv[0]);
goto BadUsage;
}
rgpszName[dwNameCnt++] = argv[0];
}
}
printf("command line: %s\n", GetCommandLine());
if (0 == dwNameCnt) {
printf("Missing <TestName>\n");
goto BadUsage;
} else
pszTestName = rgpszName[TEST_NAME_INDEX];
if (0 == _stricmp("PurgeLMRoots", pszTestName)) {
printf("Purge LocalMachine Duplicate Roots from CurrentUser\n");
if (!I_CertProtectFunction(
CERT_PROT_PURGE_LM_ROOTS_FUNC_ID,
0, // dwFlags
NULL, // pwszIn
NULL, // pbIn
0, // cbIn
NULL, // ppbOut
NULL // pcbOut
))
PrintLastError(
"I_CertProtectFunction(CERT_PROT_PURGE_LM_ROOTS_FUNC_ID)");
goto SuccessReturn;
} else if (0 == _stricmp("DeleteUnknownRoots", pszTestName)) {
printf("Delete unknown CurrentUser roots from Protected List\n");
if (!I_CertProtectFunction(
CERT_PROT_DELETE_UNKNOWN_ROOTS_FUNC_ID,
0, // dwFlags
NULL, // pwszIn
NULL, // pbIn
0, // cbIn
NULL, // ppbOut
NULL // pcbOut
))
PrintLastError(
"I_CertProtectFunction(CERT_PROT_DELETE_UNKNOWN_ROOTS_FUNC_ID)");
goto SuccessReturn;
} else if (0 == _stricmp("CheckProtectedRoots", pszTestName)) {
printf("Check ProtectedRoots ACLs\n");
CheckProtectedRoots();
goto SuccessReturn;
} else if (0 == _stricmp("ServiceUI", pszTestName)) {
BYTE *pbOut = NULL;
DWORD cbOut = 0;
printf("Certificate Protect Service UI\n");
if (!I_CertProtectFunction(
1000,
0, // dwFlags
L"Root test", // pwszIn
NULL, // pbIn
0, // cbIn
&pbOut,
&cbOut
))
PrintLastError("I_CertProtectFunction(UI)");
else if (pbOut) {
PrintBytes("DataOut", pbOut, cbOut);
CryptMemFree(pbOut);
}
goto SuccessReturn;
} else if (0 == _stricmp("ServiceTokenInfo", pszTestName)) {
BYTE *pbOut = NULL;
DWORD cbOut = 0;
printf("Certificate Protect Service's Token Info\n");
if (!I_CertProtectFunction(
1001,
0, // dwFlags
NULL, // pwszIn
NULL, // pbIn
0, // cbIn
&pbOut,
&cbOut
))
PrintLastError("I_CertProtectFunction(GetTokenInfo)");
else if (pbOut) {
if (cbOut)
puts((LPCSTR) pbOut);
CryptMemFree(pbOut);
}
goto SuccessReturn;
} else if (0 == _stricmp("ServiceInvalid", pszTestName)) {
printf("Calling Invalid Certificate Protect Function\n");
if (!I_CertProtectFunction(
1002,
0, // dwFlags
NULL, // pwszIn
NULL, // pbIn
0, // cbIn
NULL, // ppbOut
NULL // pcbOut
))
PrintLastError("I_CertProtectFunction(1002)");
goto SuccessReturn;
} else if (1 == dwNameCnt) {
printf("Missing <RegPath>\n");
goto BadUsage;
} else
pszRegPath = rgpszName[PATH_NAME_INDEX];
printf("\n");
if (0 == _stricmp("GetKey", pszTestName)) {
LONG err;
REGSAM samDesired = READ_CONTROL | ACCESS_SYSTEM_SECURITY;
SECURITY_INFORMATION SecInf = OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
SACL_SECURITY_INFORMATION;
if (!SetCurrentPrivilege(SE_SECURITY_NAME, TRUE)) {
PrintLastError("SetCurrentPrivilege(SE_SECURITY_NAME)");
samDesired = READ_CONTROL;
SecInf &= ~SACL_SECURITY_INFORMATION;
}
if (!SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE))
PrintLastError("SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME)");
GetProcessTokenInfo();
printf("\n\nGet Registry Key Security Information\n\n");
if (ERROR_SUCCESS != (err = RegOpenKeyExA(
hKeyBase,
pszRegPath,
0, // dwReserved
KEY_READ | samDesired,
&hKey))) {
if (ERROR_ACCESS_DENIED == err) {
if (ERROR_SUCCESS == (err = RegOpenKeyExA(
hKeyBase,
pszRegPath,
0, // dwReserved
samDesired,
&hKey))) {
printf("No Read Access\n");
fRecurse = FALSE;
}
}
}
if (ERROR_SUCCESS != err) {
printf("RegOpenKeyExA(%s\\%s) failed => 0x%x (%d)\n",
pszKeyBase, pszRegPath, err, err);
hKey = NULL;
} else
DisplayRegSecurityInfo(
hKey,
pszKeyBase,
pszRegPath,
SecInf,
fRecurse
);
} else if (0 == _stricmp("SetKey", pszTestName)) {
printf("Set Registry Key Security Information\n\n");
SetOwner(hKeyBase, pszRegPath);
SetGroupDaclSacl(hKeyBase, pszRegPath);
} else {
printf("Invalid TestName: %s\n", pszTestName);
goto BadUsage;
}
SuccessReturn:
status = 0;
CommonReturn:
if (hKey)
RegCloseKey(hKey);
return status;
BadUsage:
Usage();
status = -1;
goto CommonReturn;
}