1065 lines
32 KiB
C
1065 lines
32 KiB
C
//Copyright (c) 1998 - 1999 Microsoft Corporation
|
|
/*******************************************************************************
|
|
*
|
|
* security.c
|
|
*
|
|
* WinStation ACL editing functions (based on code from NT PRINTMAN security.c)
|
|
*
|
|
* copyright notice: Copyright 1995, Citrix Systems Inc.
|
|
*
|
|
* $Author: donm $ Butch Davis
|
|
*
|
|
* $Log: N:\nt\private\utils\citrix\winutils\tscfg\VCS\security.c $
|
|
*
|
|
* Rev 1.12 19 Mar 1998 16:38:40 donm
|
|
* was looking for old help file
|
|
*
|
|
* Rev 1.11 20 Sep 1996 20:37:18 butchd
|
|
* update
|
|
*
|
|
* Rev 1.10 19 Sep 1996 15:58:44 butchd
|
|
* update
|
|
*
|
|
* Rev 1.9 12 Sep 1996 16:16:38 butchd
|
|
* update
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/*
|
|
* We must compile for UNICODE because of ACL edit structures & interface, which
|
|
* is UNICODE-only.
|
|
*/
|
|
#ifndef UNICODE
|
|
#define UNICODE 1
|
|
#endif
|
|
#ifndef _UNICODE
|
|
#define _UNICODE 1
|
|
#endif
|
|
|
|
/*
|
|
* include files
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <wchar.h>
|
|
#include <sedapi.h>
|
|
|
|
#include <winsta.h>
|
|
#include "defines.h"
|
|
#include "resource.h"
|
|
#include "security.h"
|
|
#include "common.h"
|
|
#include <utildll.h>
|
|
|
|
/*
|
|
* Global variables for WINUTILS Common functions.
|
|
*/
|
|
LPCTSTR WinUtilsAppName;
|
|
HWND WinUtilsAppWindow;
|
|
HINSTANCE WinUtilsAppInstance;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// typedefs, defines, persistant storage, and private function prototypes
|
|
|
|
/*
|
|
* Indexes into the APPLICATION_ACCESSES structure:
|
|
*/
|
|
#define PERMS_SPECIAL_QUERY 0 /* query information access */
|
|
#define PERMS_SPECIAL_SET 1 /* set information access */
|
|
#define PERMS_SPECIAL_RESET 2 /* reset access */
|
|
#define PERMS_SPECIAL_SHADOW 3 /* shadow access */
|
|
#define PERMS_SPECIAL_LOGON 4 /* logon access */
|
|
#define PERMS_SPECIAL_LOGOFF 5 /* logoff access */
|
|
#define PERMS_SPECIAL_MSG 6 /* message access */
|
|
#define PERMS_SPECIAL_CONNECT 7 /* connect access */
|
|
#define PERMS_SPECIAL_DISCONNECT 8 /* disconnect access */
|
|
#define PERMS_SPECIAL_DELETE 9 /* delete access */
|
|
|
|
#define PERMS_RESOURCE_NOACCESS 10 /* no access grouping */
|
|
#define PERMS_RESOURCE_GUEST 11 /* guest access grouping */
|
|
#define PERMS_RESOURCE_USER 12 /* user access grouping */
|
|
#define PERMS_RESOURCE_ADMIN 13 /* all (admin) access grouping */
|
|
|
|
#define PERMS_COUNT 14 /* Total number of permissions */
|
|
|
|
|
|
/*
|
|
* Typedefs and static storage.
|
|
*/
|
|
typedef struct _SECURITY_CONTEXT
|
|
{
|
|
PWINSTATIONNAME pWSName;
|
|
}
|
|
SECURITY_CONTEXT, *PSECURITY_CONTEXT;
|
|
|
|
/*
|
|
* We need this structure even though we're not doing generic access mapping.
|
|
*/
|
|
GENERIC_MAPPING GenericMapping =
|
|
{ /* GenericMapping: */
|
|
GENERIC_READ, /* GenericRead */
|
|
GENERIC_WRITE, /* GenericWrite */
|
|
GENERIC_EXECUTE, /* GenericExecute */
|
|
GENERIC_ALL /* GenericAll */
|
|
};
|
|
|
|
WCHAR szLWinCfgHlp[] = L"TSCFG.HLP";
|
|
TCHAR szAclEdit[] = TEXT("ACLEDIT"); /* DLL containing ACL Edit Dialog */
|
|
char szSedDiscretionaryAclEditor[] = "SedDiscretionaryAclEditor";
|
|
|
|
LPWSTR pwstrWinStation = NULL;
|
|
LPWSTR pwstrSpecial = NULL;
|
|
|
|
#define IDD_BASE 0x20000 // makehelp.bat uses this base offset to form HIDD_ symbol
|
|
SED_HELP_INFO PermissionsHelpInfo =
|
|
{ /* HelpInfo */
|
|
szLWinCfgHlp,
|
|
IDD_HELP_PERMISSIONS_MAIN+IDD_BASE,
|
|
IDD_HELP_PERMISSIONS_SPECIAL_ACCESS+IDD_BASE,
|
|
0,
|
|
IDD_HELP_PERMISSIONS_ADD_USER+IDD_BASE,
|
|
IDD_HELP_PERMISSIONS_LOCAL_GROUP+IDD_BASE,
|
|
IDD_HELP_PERMISSIONS_GLOBAL_GROUP+IDD_BASE,
|
|
IDD_HELP_PERMISSIONS_FIND_ACCOUNT+IDD_BASE
|
|
};
|
|
|
|
|
|
SED_OBJECT_TYPE_DESCRIPTOR ObjectTypeDescriptor =
|
|
{
|
|
SED_REVISION1, /* Revision */
|
|
FALSE, /* IsContainer */
|
|
FALSE, /* AllowNewObjectPerms */
|
|
FALSE, /* MapSpecificPermsToGeneric */
|
|
&GenericMapping, /* GenericMapping */
|
|
NULL, /* GenericMappingNewObjects */
|
|
NULL, /* ObjectTypeName */
|
|
NULL, /* HelpInfo */
|
|
NULL, /* ApplyToSubContainerTitle */
|
|
NULL, /* ApplyToObjectsTitle */
|
|
NULL, /* ApplyToSubContainerConfirmation */
|
|
NULL, /* SpecialObjectAccessTitle */
|
|
NULL /* SpecialNewObjectAccessTitle */
|
|
};
|
|
|
|
/*
|
|
* Application accesses passed to the discretionary ACL editor.
|
|
*/
|
|
SED_APPLICATION_ACCESS pDiscretionaryAccessGroup[PERMS_COUNT] =
|
|
{
|
|
/* query (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL, /* Type */
|
|
WINSTATION_QUERY, /* AccessMask1 */
|
|
0, /* AccessMask2 */
|
|
NULL /* PermissionTitle */
|
|
},
|
|
|
|
/* set (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_SET,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* reset (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_RESET,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* shadow (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_SHADOW,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* logon (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_LOGON,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* logoff (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_LOGOFF,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* message (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_MSG,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* connect (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_CONNECT,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* disconnect (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
WINSTATION_DISCONNECT,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* delete (Special...)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE_SPECIAL,
|
|
DELETE,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* no access (grouping):
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE,
|
|
0,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* guest access (grouping)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE,
|
|
WINSTATION_GUEST_ACCESS,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* user access (grouping)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE,
|
|
WINSTATION_USER_ACCESS,
|
|
0,
|
|
NULL
|
|
},
|
|
|
|
/* administrator access (grouping)
|
|
*/
|
|
{
|
|
SED_DESC_TYPE_RESOURCE,
|
|
GENERIC_ALL, // maps to WINSTATION_ALL_ACCESS on WinStationOpen()
|
|
0,
|
|
NULL
|
|
}
|
|
};
|
|
|
|
#define PRIV_SECURITY 0
|
|
#define PRIV_COUNT 1
|
|
|
|
LUID SecurityValue;
|
|
|
|
/*
|
|
* Definitions from SEDAPI.H:
|
|
* (unfortunately we have to do this if we want to link dynamically)
|
|
*/
|
|
typedef DWORD (WINAPI *SED_DISCRETIONARY_ACL_EDITOR)(
|
|
HWND Owner,
|
|
HANDLE Instance,
|
|
LPWSTR Server,
|
|
PSED_OBJECT_TYPE_DESCRIPTOR ObjectType,
|
|
PSED_APPLICATION_ACCESSES ApplicationAccesses,
|
|
LPWSTR ObjectName,
|
|
PSED_FUNC_APPLY_SEC_CALLBACK ApplySecurityCallbackRoutine,
|
|
ULONG CallbackContext,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
BOOLEAN CouldntReadDacl,
|
|
BOOLEAN CantWriteDacl,
|
|
LPDWORD SEDStatusReturn,
|
|
DWORD Flags
|
|
);
|
|
|
|
SED_DISCRETIONARY_ACL_EDITOR lpfnSedDiscretionaryAclEditor = NULL;
|
|
|
|
/*
|
|
* Private function prototypes (public prototypes are in security.h).
|
|
*/
|
|
DWORD SetWinStationSecurity( PWINSTATIONNAME pWSName,
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor );
|
|
DWORD ValidateSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor);
|
|
FARPROC LoadLibraryGetProcAddress( HWND hwnd,
|
|
LPTSTR LibraryName,
|
|
LPCSTR ProcName,
|
|
PHANDLE phLibrary );
|
|
void InitializeSecurityStrings( );
|
|
VOID ReportSecurityFailure(HWND hwnd, DWORD ErrorResource, LPCTSTR String, DWORD Error);
|
|
LPVOID AllocSplMem( DWORD cb );
|
|
BOOL FreeSplMem( LPVOID pMem );
|
|
LPWSTR GetUnicodeString( int id );
|
|
DWORD WINAPI SedCallback( HWND hwndParent,
|
|
HANDLE hInstance,
|
|
ULONG CallBackContext,
|
|
PSECURITY_DESCRIPTOR pNewSecurityDescriptor,
|
|
PSECURITY_DESCRIPTOR pSecDescNewObjects,
|
|
BOOLEAN ApplyToSubContainers,
|
|
BOOLEAN ApplyToSubObjects,
|
|
LPDWORD StatusReturn );
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// public functions
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* CallPermissionsDialog (public function)
|
|
*
|
|
* Call the SedDiscretionaryAclEditor() function in ACLEDIT dll.
|
|
*
|
|
* ENTRY:
|
|
* hwnd (input)
|
|
* window handle of parent for ACL edit dialog.
|
|
* bAdmin (input)
|
|
* TRUE if user is an Administrator (can write to WinStation registry)
|
|
* FALSE otherwise (permissions will be read-only).
|
|
* pWSName (input)
|
|
* Name of WinStation to edit security for.
|
|
* EXIT:
|
|
* (BOOL) TRUE if any winstations were modified; FALSE otherwise.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOL
|
|
CallPermissionsDialog( HWND hwnd,
|
|
BOOL bAdmin,
|
|
PWINSTATIONNAME pWSName )
|
|
{
|
|
SECURITY_CONTEXT SecurityContext;
|
|
BOOLEAN CantWriteDacl;
|
|
SED_APPLICATION_ACCESSES ApplicationAccesses;
|
|
HANDLE hLibrary;
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor;
|
|
DWORD Status = SED_STATUS_NOT_MODIFIED;
|
|
DWORD Error;
|
|
HCURSOR hOldCursor;
|
|
|
|
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
/*
|
|
* Get the current WinStation security
|
|
*/
|
|
if ( (Error = GetWinStationSecurity(pWSName, &pSecurityDescriptor)) != ERROR_SUCCESS ) {
|
|
|
|
ReportSecurityFailure( hwnd,
|
|
IDP_ERROR_GET_SECURITY_WINSTATION,
|
|
pWSName, Error );
|
|
|
|
SetCursor(hOldCursor);
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* If we're not allowed access to write to WinStation registry, flag such.
|
|
*/
|
|
CantWriteDacl = !(BOOL)bAdmin;
|
|
|
|
if( !lpfnSedDiscretionaryAclEditor )
|
|
lpfnSedDiscretionaryAclEditor =
|
|
(SED_DISCRETIONARY_ACL_EDITOR)LoadLibraryGetProcAddress(
|
|
hwnd, szAclEdit, szSedDiscretionaryAclEditor, &hLibrary);
|
|
|
|
if( lpfnSedDiscretionaryAclEditor )
|
|
{
|
|
InitializeSecurityStrings( );
|
|
|
|
ObjectTypeDescriptor.ObjectTypeName = pwstrWinStation;
|
|
|
|
/*
|
|
* Pass all the permissions to the ACL editor,
|
|
* and set up the type required:
|
|
*/
|
|
ApplicationAccesses.Count = PERMS_COUNT;
|
|
ApplicationAccesses.AccessGroup = pDiscretionaryAccessGroup;
|
|
ApplicationAccesses.DefaultPermName =
|
|
pDiscretionaryAccessGroup[PERMS_RESOURCE_USER].PermissionTitle;
|
|
|
|
ObjectTypeDescriptor.HelpInfo = &PermissionsHelpInfo;
|
|
ObjectTypeDescriptor.SpecialObjectAccessTitle = pwstrSpecial;
|
|
|
|
SecurityContext.pWSName = pWSName;
|
|
Error = (*lpfnSedDiscretionaryAclEditor )
|
|
(hwnd, NULL, NULL, &ObjectTypeDescriptor,
|
|
&ApplicationAccesses, pWSName,
|
|
(PSED_FUNC_APPLY_SEC_CALLBACK)SedCallback,
|
|
(ULONG)&SecurityContext,
|
|
pSecurityDescriptor,
|
|
FALSE, CantWriteDacl,
|
|
&Status, 0);
|
|
|
|
if( Error != ERROR_SUCCESS )
|
|
ReportSecurityFailure(hwnd, IDP_ERROR_PERMISSIONS_EDITOR_FAILED, NULL, Error);
|
|
}
|
|
|
|
SetCursor(hOldCursor);
|
|
LocalFree(pSecurityDescriptor);
|
|
|
|
return( ((Status == SED_STATUS_NOT_MODIFIED) ||
|
|
(Status == SED_STATUS_NOT_ALL_MODIFIED)) ? FALSE : TRUE );
|
|
|
|
} // end CallPermissionsDialog
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* GetWinStationSecurityA (public function - ANSI stub)
|
|
*
|
|
* (see GetWinStationSecurityW)
|
|
*
|
|
* ENTRY:
|
|
* (see GetWinStationSecurityW)
|
|
* EXIT:
|
|
* (see GetWinStationSecurityW)
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD
|
|
GetWinStationSecurityA( PWINSTATIONNAMEA pWSName,
|
|
PSECURITY_DESCRIPTOR *ppSecurityDescriptor )
|
|
{
|
|
WINSTATIONNAMEW WSNameW;
|
|
|
|
/*
|
|
* Copy ANSI WinStation name to UNICODE and call GetWinStationNameW().
|
|
*/
|
|
mbstowcs(WSNameW, pWSName, sizeof(WSNameW));
|
|
|
|
return( GetWinStationSecurityW(WSNameW, ppSecurityDescriptor) );
|
|
|
|
} // GetWinStationSecurityA
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* GetWinStationSecurityW (public function - UNICODE)
|
|
*
|
|
* Obtain the security descriptor for the specified WinStation. If the
|
|
* WinStation does not have a security descriptor associated with it,
|
|
* will quietly call GetDefaultWinStationSecurity() to get the default
|
|
* security descriptor for it.
|
|
*
|
|
* ENTRY:
|
|
* pWSName (input)
|
|
* UNICODE name of WinStation to get security descriptor for.
|
|
* ppSecurityDescriptor (output)
|
|
* on success, set to pointer to allocated memory containing the
|
|
* WinStation's security descriptor.
|
|
* EXIT:
|
|
* ERROR_SUCCESS if all is OK; error code and *pSecurityDescriptor set to
|
|
* NULL if error.
|
|
*
|
|
* NOTE: on success, the memory pointed to by *ppSecurityDescriptor should be
|
|
* LocalFree()'d by the caller when the security descriptor is no longer
|
|
* needed.
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD
|
|
GetWinStationSecurityW( PWINSTATIONNAMEW pWSName,
|
|
PSECURITY_DESCRIPTOR *ppSecurityDescriptor )
|
|
{
|
|
DWORD Error, SDLength, SDLengthRequired;
|
|
|
|
*ppSecurityDescriptor = NULL;
|
|
if ( (Error = RegWinStationQuerySecurity( SERVERNAME_CURRENT,
|
|
pWSName,
|
|
NULL,
|
|
0, &SDLengthRequired ))
|
|
== ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
if ( !(*ppSecurityDescriptor =
|
|
(PSECURITY_DESCRIPTOR)LocalAlloc(
|
|
0, SDLength = SDLengthRequired)) ) {
|
|
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
Error = RegWinStationQuerySecurity( SERVERNAME_CURRENT,
|
|
pWSName,
|
|
*ppSecurityDescriptor,
|
|
SDLength, &SDLengthRequired );
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Unexpected error. If 'not found', fetch the default WinStation SD.
|
|
*/
|
|
if ( Error == ERROR_FILE_NOT_FOUND )
|
|
return( GetDefaultWinStationSecurity(ppSecurityDescriptor) );
|
|
}
|
|
|
|
/*
|
|
* Check for a valid SD before returning.
|
|
*/
|
|
if ( Error == ERROR_SUCCESS ) {
|
|
|
|
Error = ValidateSecurityDescriptor(*ppSecurityDescriptor);
|
|
|
|
} else if ( *ppSecurityDescriptor ) {
|
|
|
|
LocalFree(*ppSecurityDescriptor);
|
|
*ppSecurityDescriptor = NULL;
|
|
}
|
|
|
|
return(Error);
|
|
|
|
} // GetWinStationSecurityW
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* GetDefaultWinStationSecurity (public function)
|
|
*
|
|
* Obtain the default WinStation security descriptor.
|
|
*
|
|
* ENTRY:
|
|
* ppSecurityDescriptor (output)
|
|
* on success, set to pointer to allocated memory containing the
|
|
* default WinStation security descriptor.
|
|
* EXIT:
|
|
* ERROR_SUCCESS if all is OK; error code and *pSecurityDescriptor set to
|
|
* NULL if error.
|
|
*
|
|
* NOTE: on success, the memory pointed to by *ppSecurityDescriptor should be
|
|
* LocalFree()'d by the caller when the security descriptor is no longer
|
|
* needed.
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD
|
|
GetDefaultWinStationSecurity( PSECURITY_DESCRIPTOR *ppSecurityDescriptor )
|
|
{
|
|
DWORD Error, SDLength, SDLengthRequired;
|
|
|
|
*ppSecurityDescriptor = NULL;
|
|
if ( (Error = RegWinStationQueryDefaultSecurity( SERVERNAME_CURRENT,
|
|
NULL,
|
|
0, &SDLengthRequired ))
|
|
== ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
if ( !(*ppSecurityDescriptor =
|
|
(PSECURITY_DESCRIPTOR)LocalAlloc(
|
|
0, SDLength = SDLengthRequired)) ) {
|
|
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
Error = RegWinStationQueryDefaultSecurity( SERVERNAME_CURRENT,
|
|
*ppSecurityDescriptor,
|
|
SDLength, &SDLengthRequired );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for a valid SD before returning.
|
|
*/
|
|
if ( Error == ERROR_SUCCESS ) {
|
|
|
|
Error = ValidateSecurityDescriptor(*ppSecurityDescriptor);
|
|
|
|
} else if ( *ppSecurityDescriptor ) {
|
|
|
|
LocalFree(*ppSecurityDescriptor);
|
|
*ppSecurityDescriptor = NULL;
|
|
}
|
|
|
|
return(Error);
|
|
|
|
} // GetDefaultWinStationSecurity
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FreeSecurityStrings (public function)
|
|
*
|
|
* Free allocated memory for ACL edit string resources. This function
|
|
* should be called when the application exits.
|
|
*
|
|
* ENTRY:
|
|
* EXIT:
|
|
*
|
|
******************************************************************************/
|
|
|
|
void
|
|
FreeSecurityStrings( )
|
|
{
|
|
/*
|
|
* Only perform free if the strings have been allocated and loaded.
|
|
*/
|
|
if( pwstrWinStation )
|
|
{
|
|
FreeSplMem(pwstrWinStation);
|
|
FreeSplMem(pwstrSpecial);
|
|
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_QUERY].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_SET].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_RESET].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_SHADOW].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_LOGON].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_LOGOFF].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_MSG].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_CONNECT].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_DISCONNECT].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_SPECIAL_DELETE].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_RESOURCE_NOACCESS].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_RESOURCE_GUEST].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_RESOURCE_USER].PermissionTitle);
|
|
FreeSplMem(pDiscretionaryAccessGroup[PERMS_RESOURCE_ADMIN].PermissionTitle);
|
|
}
|
|
|
|
} // end FreeSecurityStrings
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// private functions
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* InitializeSecurityStrings (private function)
|
|
*
|
|
* Allocate and load ACL editing string resources if not done already.
|
|
* The application should call the public FreeSecurityStrings() function
|
|
* to free allocated memory when the application exits.
|
|
*
|
|
* ENTRY:
|
|
* EXIT:
|
|
*
|
|
******************************************************************************/
|
|
|
|
void
|
|
InitializeSecurityStrings()
|
|
{
|
|
if( !pwstrWinStation )
|
|
{
|
|
pwstrWinStation = GetUnicodeString(IDS_WINSTATION);
|
|
pwstrSpecial = GetUnicodeString(IDS_SPECIALACCESS);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_QUERY].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_QUERY);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_SET].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_SET);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_RESET].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_RESET);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_SHADOW].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_SHADOW);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_LOGON].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_LOGON);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_LOGOFF].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_LOGOFF);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_MSG].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_MSG);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_CONNECT].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_CONNECT);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_DISCONNECT].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_DISCONNECT);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_SPECIAL_DELETE].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_SPECIAL_DELETE);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_RESOURCE_NOACCESS].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_RESOURCE_NOACCESS);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_RESOURCE_GUEST].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_RESORUCE_GUEST);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_RESOURCE_USER].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_RESORUCE_USER);
|
|
|
|
pDiscretionaryAccessGroup[PERMS_RESOURCE_ADMIN].PermissionTitle =
|
|
GetUnicodeString(IDS_PERMS_RESOURCE_ADMIN);
|
|
}
|
|
|
|
} // end InitializeSecurityStrings
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ReportSecurityFailure (private function)
|
|
*
|
|
* Output an appropriate error message for security failure.
|
|
*
|
|
* ENTRY:
|
|
* hwnd (input)
|
|
* window handle of parent for message box.
|
|
* ErrorResource (input)
|
|
* resource ID of error format string.
|
|
* String (input)
|
|
* If not NULL, points to string to output as part of message.
|
|
* Error (input)
|
|
* Error code
|
|
* EXIT:
|
|
*
|
|
* NOTE: all ErrorResource format strings should specify a %d for Error code
|
|
* and %S for system error message string as the last two substitution
|
|
* arguments. The %S is optional, and must be present in the format
|
|
* string if the String argument is non-NULL.
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
ReportSecurityFailure(HWND hwnd, DWORD ErrorResource, LPCTSTR String, DWORD Error)
|
|
{
|
|
HWND hwndSave = WinUtilsAppWindow;
|
|
|
|
/*
|
|
* Set parent window in WinUtilsAppWindow global for use
|
|
* by STANDARD_ERROR_MESSAGE macro (StandardErrorMessage function).
|
|
*/
|
|
WinUtilsAppWindow = hwnd;
|
|
|
|
if ( String )
|
|
STANDARD_ERROR_MESSAGE((WINAPPSTUFF, LOGONID_NONE, Error, ErrorResource, String))
|
|
else
|
|
STANDARD_ERROR_MESSAGE((WINAPPSTUFF, LOGONID_NONE, Error, ErrorResource))
|
|
|
|
/*
|
|
* Restore original WinUtilsAppWindow to global.
|
|
*/
|
|
WinUtilsAppWindow = hwndSave;
|
|
|
|
} // end ReportSecurityFailure
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SedCallback (private function)
|
|
*
|
|
* Callback function from ACL edit dialog DLL
|
|
*
|
|
* ENTRY:
|
|
* (see sedapi.h)
|
|
* EXIT:
|
|
* (see sedapi.h)
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD WINAPI
|
|
SedCallback( HWND hwndParent,
|
|
HANDLE hInstance,
|
|
ULONG CallBackContext,
|
|
PSECURITY_DESCRIPTOR pUpdatedSecurityDescriptor,
|
|
PSECURITY_DESCRIPTOR pSecDescNewObjects,
|
|
BOOLEAN ApplyToSubContainers,
|
|
BOOLEAN ApplyToSubObjects,
|
|
LPDWORD StatusReturn )
|
|
{
|
|
WINSTATIONNAME WSName;
|
|
PSECURITY_CONTEXT pSecurityContext;
|
|
DWORD Error;
|
|
BOOL OK = TRUE;
|
|
|
|
pSecurityContext = (PSECURITY_CONTEXT)CallBackContext;
|
|
|
|
/*
|
|
* Apply security to the WinStation.
|
|
*/
|
|
lstrcpy(WSName, pSecurityContext->pWSName);
|
|
if ( (Error = SetWinStationSecurity( WSName,
|
|
pUpdatedSecurityDescriptor))
|
|
!= ERROR_SUCCESS ) {
|
|
|
|
ReportSecurityFailure( hwndParent,
|
|
IDP_ERROR_SET_SECURITY_WINSTATION,
|
|
WSName,
|
|
Error );
|
|
OK = FALSE;
|
|
*StatusReturn = SED_STATUS_NOT_ALL_MODIFIED;
|
|
}
|
|
|
|
if ( OK == TRUE )
|
|
*StatusReturn = SED_STATUS_MODIFIED;
|
|
|
|
return( OK ? 0 : 1 );
|
|
|
|
} // end SedCallback
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* LoadLibraryGetProcAddress (private function)
|
|
*
|
|
* Load the specified library and retrieve FARPROC pointer to specified
|
|
* procedure's entry point.
|
|
*
|
|
* ENTRY:
|
|
* hwnd (input)
|
|
* window handle of owner for error message display
|
|
* LibraryName (input)
|
|
* name of library dll to load
|
|
* ProcName (input)
|
|
* name of library procedure to reference
|
|
* phLibrary (output)
|
|
* set to handle of loaded library on return
|
|
* EXIT:
|
|
* FARPROC pointer to library procedure's entry point.
|
|
*
|
|
******************************************************************************/
|
|
|
|
FARPROC
|
|
LoadLibraryGetProcAddress( HWND hwnd,
|
|
LPTSTR LibraryName,
|
|
LPCSTR ProcName,
|
|
PHANDLE phLibrary )
|
|
{
|
|
HANDLE hLibrary;
|
|
FARPROC lpfn = NULL;
|
|
|
|
hLibrary = LoadLibrary(LibraryName);
|
|
|
|
if ( hLibrary ) {
|
|
|
|
lpfn = GetProcAddress(hLibrary, ProcName);
|
|
|
|
if(!lpfn) {
|
|
|
|
ERROR_MESSAGE(( IDP_ERROR_COULDNOTFINDPROCEDURE,
|
|
ProcName, LibraryName ))
|
|
FreeLibrary(hLibrary);
|
|
}
|
|
|
|
} else
|
|
ERROR_MESSAGE((IDP_ERROR_COULDNOTLOADLIBRARY, LibraryName))
|
|
|
|
*phLibrary = hLibrary;
|
|
|
|
return(lpfn);
|
|
|
|
} // end LoadLibraryGetProcAddress
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* AllocSplMem (private function)
|
|
*
|
|
* Allocate and zero-fill specified amount of memory.
|
|
*
|
|
* ENTRY:
|
|
* cb (input)
|
|
* number of bytes to allocate
|
|
* EXIT:
|
|
* LPVOID pointer to allocated memory; NULL if error.
|
|
*
|
|
******************************************************************************/
|
|
|
|
LPVOID
|
|
AllocSplMem( DWORD cb )
|
|
{
|
|
return(LocalAlloc(LPTR, cb));
|
|
|
|
} // end AllocSplMem
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FreeSplMem (private function)
|
|
*
|
|
* Free the specified memory block.
|
|
*
|
|
* ENTRY:
|
|
* pMem (input)
|
|
* memory to free
|
|
* EXIT:
|
|
* TRUE if sucess; FALSE if error.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOL
|
|
FreeSplMem( LPVOID pMem )
|
|
{
|
|
return( LocalFree((HLOCAL)pMem) == NULL );
|
|
|
|
} // end FreeSplMem
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* GetUnicodeString (private function)
|
|
*
|
|
* Load a resource string and allocate/save in memory block.
|
|
*
|
|
* ENTRY:
|
|
* id (input)
|
|
* resource id of string to get
|
|
* EXIT:
|
|
* pointer to allocated and loaded UNICODE string
|
|
*
|
|
******************************************************************************/
|
|
|
|
LPWSTR
|
|
GetUnicodeString(int id)
|
|
{
|
|
WCHAR ResString[256];
|
|
DWORD length = 0;
|
|
LPWSTR pUnicode;
|
|
DWORD cbUnicode;
|
|
|
|
length = LoadStringW(NULL, id, ResString, 256);
|
|
|
|
cbUnicode = (length * sizeof(WCHAR)) + sizeof(WCHAR);
|
|
pUnicode = AllocSplMem(cbUnicode);
|
|
|
|
if( pUnicode )
|
|
memcpy(pUnicode, ResString, cbUnicode);
|
|
|
|
return(pUnicode);
|
|
|
|
} // end GetUnicodeString
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ValidateSecurityDescriptor (private function)
|
|
*
|
|
* Check the specified security descriptor for valid structure as well as
|
|
* valid ACLs and SIDs.
|
|
*
|
|
* ENTRY:
|
|
* pSecurityDescriptor (input)
|
|
* Security descriptor to validate.
|
|
* EXIT:
|
|
* ERROR_SUCCESS if valid; error otherwise.
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD
|
|
ValidateSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
|
|
if ( !IsValidSecurityDescriptor(pSecurityDescriptor) ) {
|
|
|
|
Error = GetLastError();
|
|
|
|
} else {
|
|
|
|
BOOL bAclPresent, bDefaulted;
|
|
PACL pACL;
|
|
PSID pSID;
|
|
|
|
for ( ; ; ) {
|
|
|
|
if ( !GetSecurityDescriptorDacl( pSecurityDescriptor,
|
|
&bAclPresent, &pACL, &bDefaulted ) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
if ( bAclPresent && pACL )
|
|
if ( !IsValidAcl(pACL) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if ( !GetSecurityDescriptorSacl( pSecurityDescriptor,
|
|
&bAclPresent, &pACL, &bDefaulted ) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
if ( bAclPresent && pACL )
|
|
if ( !IsValidAcl(pACL) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if ( !GetSecurityDescriptorOwner( pSecurityDescriptor,
|
|
&pSID, &bDefaulted ) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
if ( pSID )
|
|
if ( !IsValidSid(pSID) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if ( !GetSecurityDescriptorGroup( pSecurityDescriptor,
|
|
&pSID, &bDefaulted ) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
if ( pSID )
|
|
if ( !IsValidSid(pSID) ) {
|
|
Error = GetLastError();
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(Error);
|
|
|
|
} // end ValidateSecurityDescriptor
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SetWinStationSecurity (private function)
|
|
*
|
|
* Set the specified WinStation's registry and kernel object security.
|
|
*
|
|
* ENTRY:
|
|
* pWSName (input)
|
|
* Name of WinStation to set security for.
|
|
* pSecurityDescriptor (input)
|
|
* Security descriptor to set for winstation.
|
|
* EXIT:
|
|
* ERROR_SUCCESS if valid; error otherwise.
|
|
*
|
|
******************************************************************************/
|
|
|
|
DWORD
|
|
SetWinStationSecurity( PWINSTATIONNAME pWSName,
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor )
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
|
|
Error = RegWinStationSetSecurity( SERVERNAME_CURRENT,
|
|
pWSName,
|
|
pSecurityDescriptor,
|
|
GetSecurityDescriptorLength(pSecurityDescriptor) );
|
|
|
|
return(Error);
|
|
|
|
} // SetWinStationSecurity
|