HOWTO: Program a Secure Server on Windows NTLast reviewed: July 11, 1997Article ID: Q171273 |
The information in this article applies to:
SUMMARYIn the Client/Server model, it is often desirable to arbitrate access to the server's functions or data based on a client's privileges. Given an application-derived Security Descriptor (SD) that specifies a certain set of rights for a particular group of users in its Discretionary Access Control List (DACL) and a client token representing a user that wants access to the protected server, you can call the AccessCheck() API to determine if the client should be granted that access. This process is explained in detail in the section below. Sample code is provided at the end of this article. NOTE: It is assumed that you already have an understanding of Windows NT Security in general, and Access Control Security in particular.
MORE INFORMATIONTo build a simple secure server, you need to follow the following steps:
Sample Code
/* The following sample code demonstrates how to use the AccessCheck API to determine if a client token has sufficient access to perform some operation against an object protected by a Security Descriptor or to determine what the client's maximum access is on that same object. This code sample requires the following import library: advapi32.lib David Mowers (davemo) 15-May-97 */ #include <windows.h> #include <stdio.h> // // Make up some private access rights. // #define ACCESS_READ 1 #define ACCESS_WRITE 2 void main( int argc, char *argv[] ) { PSECURITY_DESCRIPTOR psdSD; // User\SID Variables: #define BUF_SIZE 256 // should be dynamic HANDLE hToken; TOKEN_USER ptuUser[BUF_SIZE]; DWORD cbBuffer=BUF_SIZE; PSID pUserSid; // ACE variables: DWORD dwAccessMask=ACCESS_READ | ACCESS_WRITE; PACL pACL; DWORD dwACLSize; // AccessCheck variables: DWORD dwAccessDesired; PRIVILEGE_SET PrivilegeSet; DWORD dwPrivSetSize; DWORD dwAccessGranted; BOOL fAccessGranted=FALSE; GENERIC_MAPPING GenericMapping; // // Get a SID for later use. A real server would use an API // like LookupAccountName() to get SIDs that you will use to // build your access control list. // OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&hToken); GetTokenInformation(hToken, TokenUser, ptuUser, cbBuffer, &cbBuffer); pUserSid = ptuUser->User.Sid; CloseHandle(hToken); // // Build a Security Descriptor. // psdSD = LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH); if(!InitializeSecurityDescriptor(psdSD,SECURITY_DESCRIPTOR_REVISION)) { printf("Error %d:InitializeSecurityDescriptor\n",GetLastError()); } // // Compute size needed for the ACL. // dwACLSize = sizeof(ACCESS_ALLOWED_ACE) + 8 + GetLengthSid(pUserSid) - sizeof(DWORD); // // Allocate memory for ACL. // pACL = (PACL)LocalAlloc(LPTR, dwACLSize); // // Initialize the new ACL. // if(!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) { printf("Error %d:InitializeAcl\n",GetLastError()); } // // Add the access-allowed ACE to the DACL. // if(!AddAccessAllowedAce(pACL,ACL_REVISION2,dwAccessMask, pUserSid)) { printf("Error %d:AddAccessAllowedAce",GetLastError()); } // // Set our DACL to the SD. // if (!SetSecurityDescriptorDacl(psdSD, TRUE, pACL, FALSE)) { printf("Error %d:SetSecurityDescriptorDacl",GetLastError()); } // // AccessCheck is picky about what is in the SD. Set // the group and owner using our convenient SID. // SetSecurityDescriptorGroup(psdSD,pUserSid,FALSE); SetSecurityDescriptorOwner(psdSD,pUserSid,FALSE); // // AccessCheck requires an impersonation token. // For demonstration purposes, we are going to impersonate // ourselves. // A real server would impersonate the client using // ImpersonateNamedPipeClient(),RPCImpersonateClient(), // ImpersonateLoggedOnUser()with a token obtained through // LogonUser() or the SSPI API ImpersonateSecurityContext(). // ImpersonateSelf(SecurityImpersonation); OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hToken ); // // Using AccessCheck, there are two different things we could // do: // // // 1. See if we have Read/Write access to the object. // dwAccessDesired = ACCESS_READ; // // Initialize GenericMapping structure to map all. // memset(&GenericMapping,0xff,sizeof(GENERIC_MAPPING)); GenericMapping.GenericRead = ACCESS_READ; GenericMapping.GenericWrite = ACCESS_WRITE; GenericMapping.GenericExecute = 0; GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; // // This only does something if we want to use generic access rights, // like GENERIC_ALL, in our call to AccessCheck. We are not. // MapGenericMask(&dwAccessDesired, &GenericMapping); dwPrivSetSize = sizeof(PRIVILEGE_SET); // // Make the call. // if( !AccessCheck(psdSD, hToken, dwAccessDesired, &GenericMapping, &PrivilegeSet, &dwPrivSetSize, &dwAccessGranted, &fAccessGranted ) ) printf("Error in AccessCheck : %lu\n", GetLastError()); else { if(fAccessGranted) printf(" Access Was Granted Using Mask %lx\n", dwAccessGranted); else printf("Access was NOT granted!\n"); } // // 2. See if what is the maximum access I am allowed. // dwAccessDesired = MAXIMUM_ALLOWED; if( !AccessCheck(psdSD, hToken, dwAccessDesired, &GenericMapping, &PrivilegeSet, &dwPrivSetSize, &dwAccessGranted, &fAccessGranted ) ) printf("Error in AccessCheck : %lu\n", GetLastError()); else { if(fAccessGranted) printf(" Maximum Access Allowed = %lx\n", dwAccessGranted); } RevertToSelf(); LocalFree(pACL); LocalFree(psdSD); } |
Keywords : BseSecurity kbcode kbprg
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |