413 lines
10 KiB
C
413 lines
10 KiB
C
/********************************************************************/
|
||
/** Copyright(c) 1989 Microsoft Corporation. **/
|
||
/********************************************************************/
|
||
|
||
//***
|
||
//
|
||
// Filename: security.c
|
||
//
|
||
// Description: This module contains code that will create and delete the
|
||
// security object. It will also contain access checking calls.
|
||
//
|
||
// History:
|
||
// June 21,1992. NarenG Created original version.
|
||
//
|
||
// NOTE: ??? The lpdwAccessStatus parameter for AccessCheckAndAuditAlarm
|
||
// returns junk. ???
|
||
//
|
||
#include "afpsvcp.h"
|
||
|
||
typedef struct _AFP_SECURITY_OBJECT {
|
||
|
||
LPWSTR lpwsObjectName;
|
||
LPWSTR lpwsObjectType;
|
||
GENERIC_MAPPING GenericMapping;
|
||
PSECURITY_DESCRIPTOR pSecurityDescriptor;
|
||
|
||
} AFP_SECURITY_OBJECT, PAFP_SECURITY_OBJECT;
|
||
|
||
static AFP_SECURITY_OBJECT AfpSecurityObject;
|
||
|
||
#define AFPSVC_SECURITY_OBJECT TEXT("AfpSvcAdminApi");
|
||
#define AFPSVC_SECURITY_OBJECT_TYPE TEXT("Security");
|
||
|
||
|
||
|
||
//**
|
||
//
|
||
// Call: AfpSecObjCreate
|
||
//
|
||
// Returns: NO_ERROR - success
|
||
// ERROR_NOT_ENOUGH_MEMORY
|
||
// non-zero returns from security functions
|
||
//
|
||
// Description: This procedure will set up the security object that will
|
||
// be used to check to see if an RPC client is an administrator
|
||
// for the local machine.
|
||
//
|
||
DWORD
|
||
AfpSecObjCreate(
|
||
VOID
|
||
)
|
||
{
|
||
PSID pAdminSid = NULL;
|
||
PSID pLocalSystemSid = NULL;
|
||
PSID pServerOpSid = NULL;
|
||
PSID pPwrUserSid = NULL;
|
||
PACL pDacl = NULL;
|
||
HANDLE hProcessToken = NULL;
|
||
PULONG pSubAuthority;
|
||
SID_IDENTIFIER_AUTHORITY SidIdentifierNtAuth = SECURITY_NT_AUTHORITY;
|
||
SECURITY_DESCRIPTOR SecurityDescriptor;
|
||
DWORD dwRetCode;
|
||
DWORD cbDaclSize;
|
||
|
||
|
||
// Set up security object
|
||
//
|
||
AfpSecurityObject.lpwsObjectName = AFPSVC_SECURITY_OBJECT;
|
||
AfpSecurityObject.lpwsObjectType = AFPSVC_SECURITY_OBJECT_TYPE;
|
||
|
||
// Generic mapping structure for the security object
|
||
// All generic access types are allowed API access.
|
||
//
|
||
AfpSecurityObject.GenericMapping.GenericRead = STANDARD_RIGHTS_READ |
|
||
AFPSVC_ALL_ACCESS;
|
||
|
||
AfpSecurityObject.GenericMapping.GenericWrite = STANDARD_RIGHTS_WRITE |
|
||
AFPSVC_ALL_ACCESS;
|
||
|
||
AfpSecurityObject.GenericMapping.GenericExecute =
|
||
STANDARD_RIGHTS_EXECUTE |
|
||
AFPSVC_ALL_ACCESS;
|
||
|
||
AfpSecurityObject.GenericMapping.GenericAll = AFPSVC_ALL_ACCESS;
|
||
|
||
// The do - while(FALSE) statement is used so that the break statement
|
||
// maybe used insted of the goto statement, to execute a clean up and
|
||
// and exit action.
|
||
//
|
||
do {
|
||
|
||
dwRetCode = NO_ERROR;
|
||
|
||
// Set up the SID for the admins that will be allowed to have
|
||
// access. This SID will have 2 sub-authorities
|
||
// SECURITY_BUILTIN_DOMAIN_RID and DOMAIN_ALIAS_ADMIN_RID.
|
||
//
|
||
pAdminSid = (PSID)LocalAlloc( LPTR, GetSidLengthRequired( 2 ) );
|
||
|
||
if ( pAdminSid == NULL ) {
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
if ( !InitializeSid( pAdminSid, &SidIdentifierNtAuth, 2 ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Set the sub-authorities
|
||
//
|
||
pSubAuthority = GetSidSubAuthority( pAdminSid, 0 );
|
||
*pSubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
pSubAuthority = GetSidSubAuthority( pAdminSid, 1 );
|
||
*pSubAuthority = DOMAIN_ALIAS_RID_ADMINS;
|
||
|
||
// Create the server operators SID
|
||
//
|
||
pServerOpSid = (PSID)LocalAlloc( LPTR, GetSidLengthRequired( 2 ) );
|
||
|
||
if ( pServerOpSid == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
if ( !InitializeSid( pServerOpSid, &SidIdentifierNtAuth, 2 ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Set the sub-authorities
|
||
//
|
||
pSubAuthority = GetSidSubAuthority( pServerOpSid, 0 );
|
||
*pSubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
pSubAuthority = GetSidSubAuthority( pServerOpSid, 1 );
|
||
*pSubAuthority = DOMAIN_ALIAS_RID_SYSTEM_OPS;
|
||
|
||
//
|
||
// Create the Power user operators SID
|
||
//
|
||
pPwrUserSid = (PSID)LocalAlloc( LPTR, GetSidLengthRequired( 2 ) );
|
||
|
||
if ( pPwrUserSid == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
if ( !InitializeSid( pPwrUserSid, &SidIdentifierNtAuth, 2 ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Set the sub-authorities
|
||
//
|
||
pSubAuthority = GetSidSubAuthority( pPwrUserSid, 0 );
|
||
*pSubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
pSubAuthority = GetSidSubAuthority( pPwrUserSid, 1 );
|
||
*pSubAuthority = DOMAIN_ALIAS_RID_POWER_USERS;
|
||
|
||
// Create the LocalSystemSid which will be the owner and the primary
|
||
// group of the security object.
|
||
//
|
||
pLocalSystemSid = (PSID)LocalAlloc( LPTR, GetSidLengthRequired( 1 ) );
|
||
|
||
if ( pLocalSystemSid == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
if ( !InitializeSid( pLocalSystemSid, &SidIdentifierNtAuth, 1 ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Set the sub-authorities
|
||
//
|
||
pSubAuthority = GetSidSubAuthority( pLocalSystemSid, 0 );
|
||
*pSubAuthority = SECURITY_LOCAL_SYSTEM_RID;
|
||
|
||
// Set up the DACL that will allow admins with the above SID all access
|
||
// It should be large enough to hold all ACEs.
|
||
//
|
||
cbDaclSize = sizeof(ACL) + ( sizeof(ACCESS_ALLOWED_ACE) * 2 ) +
|
||
GetLengthSid(pAdminSid) + GetLengthSid(pServerOpSid) + GetLengthSid(pPwrUserSid);
|
||
|
||
if ( (pDacl = (PACL)LocalAlloc( LPTR, cbDaclSize ) ) == NULL )
|
||
{
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
if ( !InitializeAcl( pDacl, cbDaclSize, ACL_REVISION2 ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Add the ACE to the DACL
|
||
//
|
||
if ( !AddAccessAllowedAce( pDacl,
|
||
ACL_REVISION2,
|
||
AFPSVC_ALL_ACCESS, // What the admin can do
|
||
pAdminSid ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
if ( !AddAccessAllowedAce( pDacl,
|
||
ACL_REVISION2,
|
||
AFPSVC_ALL_ACCESS, // What the admin can do
|
||
pServerOpSid ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
if ( !AddAccessAllowedAce( pDacl,
|
||
ACL_REVISION2,
|
||
AFPSVC_ALL_ACCESS, // What the power user can do
|
||
pPwrUserSid ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Create the security descriptor an put the DACL in it.
|
||
//
|
||
if ( !InitializeSecurityDescriptor( &SecurityDescriptor, 1 ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
if ( !SetSecurityDescriptorDacl( &SecurityDescriptor,
|
||
TRUE,
|
||
pDacl,
|
||
FALSE ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
|
||
// Set owner for the descriptor
|
||
//
|
||
if ( !SetSecurityDescriptorOwner( &SecurityDescriptor,
|
||
pLocalSystemSid,
|
||
FALSE ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
|
||
// Set group for the descriptor
|
||
//
|
||
if ( !SetSecurityDescriptorGroup( &SecurityDescriptor,
|
||
pLocalSystemSid,
|
||
FALSE ) )
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Get token for the current process
|
||
//
|
||
if ( !OpenProcessToken( GetCurrentProcess(),
|
||
TOKEN_QUERY,
|
||
&hProcessToken ))
|
||
{
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
// Create a security object. This is really just a security descriptor
|
||
// is self-relative form. This procedure will allocate memory for this
|
||
// security descriptor and copy all in the information passed in. This
|
||
// allows us to free all dynamic memory allocated.
|
||
//
|
||
if ( !CreatePrivateObjectSecurity(
|
||
NULL,
|
||
&SecurityDescriptor,
|
||
&(AfpSecurityObject.pSecurityDescriptor),
|
||
FALSE,
|
||
hProcessToken,
|
||
&(AfpSecurityObject.GenericMapping)
|
||
))
|
||
dwRetCode = GetLastError();
|
||
|
||
} while( FALSE );
|
||
|
||
|
||
// Free up the dynamic memory
|
||
//
|
||
if ( pLocalSystemSid != NULL )
|
||
LocalFree( pLocalSystemSid );
|
||
|
||
if ( pAdminSid != NULL )
|
||
LocalFree( pAdminSid );
|
||
|
||
if ( pServerOpSid != NULL )
|
||
LocalFree( pServerOpSid );
|
||
|
||
if ( pPwrUserSid != NULL )
|
||
LocalFree( pPwrUserSid );
|
||
|
||
if ( pDacl != NULL )
|
||
LocalFree( pDacl );
|
||
|
||
if ( hProcessToken != NULL )
|
||
CloseHandle( hProcessToken );
|
||
|
||
return( dwRetCode );
|
||
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpSecObjDelete
|
||
//
|
||
// Returns: NO_ERROR - success
|
||
// non-zero returns from security functions
|
||
//
|
||
// Description: Will destroy a valid security descriptor.
|
||
//
|
||
DWORD
|
||
AfpSecObjDelete( VOID )
|
||
{
|
||
if ( !IsValidSecurityDescriptor( AfpSecurityObject.pSecurityDescriptor))
|
||
return( NO_ERROR );
|
||
|
||
if (!DestroyPrivateObjectSecurity( &AfpSecurityObject.pSecurityDescriptor))
|
||
return( GetLastError() );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpSecObjAccessCheck
|
||
//
|
||
// Returns: NO_ERROR - success
|
||
// non-zero returns from security functions
|
||
//
|
||
// Description: This procedure will first impersonate the client, then
|
||
// check to see if the client has the desired access to the
|
||
// security object. If he/she does then the AccessStatus
|
||
// variable will be set to NO_ERROE otherwise it will be
|
||
// set to ERROR_ACCESS_DENIED. It will the revert to self and
|
||
// return.
|
||
//
|
||
DWORD
|
||
AfpSecObjAccessCheck( IN DWORD DesiredAccess,
|
||
OUT LPDWORD lpdwAccessStatus
|
||
)
|
||
{
|
||
DWORD dwRetCode;
|
||
ACCESS_MASK GrantedAccess;
|
||
BOOL fGenerateOnClose;
|
||
|
||
// Impersonate the client
|
||
//
|
||
dwRetCode = RpcImpersonateClient( NULL );
|
||
|
||
if ( dwRetCode != RPC_S_OK )
|
||
return( I_RpcMapWin32Status( dwRetCode ));
|
||
|
||
dwRetCode = AccessCheckAndAuditAlarm(
|
||
AFP_SERVICE_NAME,
|
||
NULL,
|
||
AfpSecurityObject.lpwsObjectType,
|
||
AfpSecurityObject.lpwsObjectName,
|
||
AfpSecurityObject.pSecurityDescriptor,
|
||
DesiredAccess,
|
||
&(AfpSecurityObject.GenericMapping),
|
||
FALSE,
|
||
&GrantedAccess,
|
||
(LPBOOL)lpdwAccessStatus,
|
||
&fGenerateOnClose
|
||
);
|
||
|
||
RpcRevertToSelf();
|
||
|
||
if ( !dwRetCode )
|
||
return( GetLastError() );
|
||
|
||
// Check if desired access == granted Access
|
||
//
|
||
if ( DesiredAccess != GrantedAccess )
|
||
{
|
||
AFP_PRINT(( "SFMSVC: AfpSecObjAccessCheck: granted = 0x%x, desired = 0x%x\n",
|
||
GrantedAccess,DesiredAccess));
|
||
*lpdwAccessStatus = ERROR_ACCESS_DENIED;
|
||
}
|
||
else
|
||
{
|
||
*lpdwAccessStatus = NO_ERROR;
|
||
}
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|