Hart.gif (5380 bytes)Win32 System Programming

Return to Addison-Wesley Home Page  


Return to Top Page

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;
}