Build Explicit Access With Name
Note: BuildExplicitAccessWithName has one very
peculiar, and undesirable, feature. It does not return any error indication at all, and it
does not appear to set the last error.
/* PROGRAM 7-3 -Modified Version - Can only be built with Visual C++ 5.0 or later
because it uses the BuildSecurityDescriptor function. */
/* InitBuildSD.c */
/* These functions maintain UNIX-style permissions
in a Win32 (Windows NT only) SECURITY_ATTRIBUTES structure.
There are three entries:
- InitializeSD, which is a new version of the old InitializeUnixSD:
Allocate & initialize a security descriptor.
The following functions are the same as before and are not listed here.
- ChangeFilePermissions: Modify file's security.
- ReadFilePermissions: Interrogate a file's security.
There are a number of assumptions and limitations:
- You can only modify and read a structure previously
created by InitializeUnixSA.
- All permissions are the UNIX style:
[R,W,X] - [User, Group, Other].
- The group is taken from the Group SID of the process.
This may really represent several groups.
You can, however, apply generic rights to ANY securable object.
- The change and read entries require the HANDLE of the
object and obtain its SA. */
#include "EvryThng.h"
#include <accctrl.h> /* You need both these header files. */
#include <aclapi.h>
#define ACL_SIZE 1024
#define DOM_SIZE LUSIZE
#define NUM_BITS 9
static VOID FindGroup (DWORD, LPTSTR);
/* FindGroup is a new function that finds the user's primary group. It solves Exercise 8-8 */
PSECURITY_DESCRIPTOR InitializeSD (DWORD UnixPerms,
LPTSTR UsrNam, LPTSTR GrpNam, LPDWORD AceMasks)
/* Create a structure and set the UNIX style permissions
as specified in UnixPerms, which is 9-bits
(low-order end) giving the required [R,W,X] settings
for [User,Group,Other] in the familiar UNIX form.
Return a pointer to a security descriptor structure. */
{
LONG iBit;
DWORD ErrNum = 0;
LPTSTR TrusteeNames [3] = { NULL, NULL, _T("EVERYONE")};
TCHAR GroupName [MAX_NAME];
TRUSTEE Trustees[2]; /* The two trustees - User, Group - for the SD */
= { { NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_USER, TrusteeNames[0] },
{ NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_GROUP, TrusteeNames[1] } };
EXPLICIT_ACCESS AccessEntries [NUM_BITS];
ULONG SizeNewSD = 0xFFFFFFFF;
PSECURITY_DESCRIPTOR pNewSD = NULL;
if (GrpNam == NULL || _tcslen(GrpNam) == 0) {
/* No group name specified. Get the user's primary group and
override initial settings. */
FindGroup (2, GroupName);
Trustees[1].ptstrName = TrusteeNames [1] = GroupName;
} else Trustees[1].ptstrName = TrusteeNames[1] = GrpNam;
printf ("Group Name: %s\n", Trustees[1].ptstrName);
/* Set all the access entry members and submembers */
for (iBit = 0; iBit < NUM_BITS /* 9 */; iBit++) {
/* COMMENT: BuildExplicitAccessWithName, inexplicably, does
not return any indicator of success or failure and does
not appear to affect GetLastError(). */
BuildExplicitAccessWithName (
&AccessEntries [iBit],
TrusteeNames [iBit / 3],
AceMasks [iBit % 3],
((UnixPerms >> (8 - iBit) & 0x1) == 1) ? GRANT_ACCESS : DENY_ACCESS,
NO_INHERITANCE);
}
if ((ErrNum = BuildSecurityDescriptor (&Trustees[0], &Trustees[1],
NUM_BITS, AccessEntries,
/* Nine Access entries corresponding to 9 permission bits. */
0, NULL, /* No Audit entries */
NULL, /* No preexisting Security Descriptor */
&SizeNewSD, &pNewSD)) != ERROR_SUCCESS) {
/* Comment: Am I the only one who finds "ERROR_SUCCESS"
to be a strange name? */
/* This function does not set the last error number. */
printf ("SizeNewSD: %d, pNewSD: %x", SizeNewSD, pNewSD);
SetLastError (ErrNum);
}
return pNewSD;
}
/* PROGRAM 7-3 ENDS HERE. */
/* This code is a solution to Exercise 8-8. */
static VOID FindGroup (DWORD GroupNumber, LPTSTR GroupName)
/* Find a group name associated with the owning user of the current process. */
{
TCHAR RefDomain [DOM_SIZE];
DWORD RefDomCnt = DOM_SIZE, AcctSize = ACCT_NAME_SIZE;
SID_NAME_USE GroupSidType = SidTypeGroup;
HANDLE tHandle;
TOKEN_GROUPS TokenG[20]; /* You need some space for this. */
DWORD TISize;
if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ALL_ACCESS, &tHandle))
ReportError (_T ("OpenProcessToken error"), 0, TRUE);
if (!GetTokenInformation (tHandle, TokenGroups,
&TokenG, sizeof (TokenG), &TISize)) {
ReportError (_T ("GetTokenInfo error"), 0, TRUE);
}
/* Experimentation shows that the groups entered are as follows:
0 - None
1 - Everyone
2 - The first non-trivial group
3,.. - Keep looking up to the count, which is part
of the structure - see the documentation! */
if (!LookupAccountSid (NULL, TokenG[0].Groups[GroupNumber].Sid,
GroupName, &AcctSize, RefDomain, &RefDomCnt, &GroupSidType))
ReportError (_T("Error looking up Account Name"), 0, TRUE);
return;
}
|