|
|
/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
sddl.c
Abstract:
This module implements the Security Descriptor Definition Language support functions
Author:
Mac McLain (MacM) Nov 07, 1997
Environment:
User Mode
Revision History:
Jin Huang (JinHuang) 3/4/98 Fix validity flags (GetAceFlagsInTable) Jin Huang (JinHuang) 3/10/98 Add SD controls (GetSDControlForString) Set SidsInitialized flag Skip any possible spaces in string Jin Huang (JinHuang) 5/1/98 Fix memory leek, error checking improve performance Alaa Abdelhalim (Alaa) 7/20/99 Initialize sbz2 field to 0 in LocalGetAclForString function. Vishnu Patankar (VishnuP) 7/5/00 Added new API ConvertStringSDToSDDomain(A/W) Shawn Wu (ShawnWu) 4/27/02 Added encrypted ldap support.
--*/ #include "advapi.h"
#include <windef.h>
#include <stdio.h>
#include <wchar.h>
#include <sddl.h>
#include <ntseapi.h>
#include <seopaque.h>
#include <accctrl.h>
#include <rpcdce.h>
#include <ntlsa.h>
#include "sddlp.h"
//
// include and defines for ldap calls
//
#include <winldap.h>
#include <ntldap.h>
typedef PLDAP (LDAPAPI *PFN_LDAP_INIT)( PCHAR HostName, ULONG PortNumber ); typedef ULONG (LDAPAPI *PFN_LDAP_SET_OPTION) ( LDAP *, int , const void * ); typedef ULONG (LDAPAPI *PFN_LDAP_BIND)( LDAP *, PCHAR, PCHAR, ULONG); typedef ULONG (LDAPAPI *PFN_LDAP_UNBIND)( LDAP * ); typedef ULONG (LDAPAPI *PFN_LDAP_SEARCH)(LDAP *, PCHAR, ULONG, PCHAR, PCHAR *, ULONG,PLDAPControlA *, PLDAPControlA *, struct l_timeval *, ULONG, LDAPMessage **); typedef LDAPMessage * (LDAPAPI *PFN_LDAP_FIRST_ENTRY)( LDAP *, LDAPMessage * ); typedef PCHAR * (LDAPAPI *PFN_LDAP_GET_VALUE)(LDAP *, LDAPMessage *, PCHAR ); typedef ULONG (LDAPAPI *PFN_LDAP_MSGFREE)( LDAPMessage * ); typedef ULONG (LDAPAPI *PFN_LDAP_VALUE_FREE)( PCHAR * ); typedef ULONG (LDAPAPI *PFN_LDAP_MAP_ERROR)( ULONG );
// 64K-1
#define SDDL_MAX_ACL_SIZE 0xFFFF
#define SDDL_SID_STRING_SIZE 256
//
// To allow the defines to be used as Wide strings, redefine the TEXT macro
//
#ifdef TEXT
#undef TEXT
#endif
#define TEXT(quote) L##quote
//
// Local macros
//
#define STRING_GUID_LEN 36
#define STRING_GUID_SIZE ( STRING_GUID_LEN * sizeof( WCHAR ) )
#define SDDL_LEN_TAG( tagdef ) ( sizeof( tagdef ) / sizeof( WCHAR ) - 1 )
#define SDDL_SIZE_TAG( tagdef ) ( wcslen( tagdef ) * sizeof( WCHAR ) )
#define SDDL_SIZE_SEP( sep ) (sizeof( WCHAR ) )
#define SDDL_VALID_DACL 0x00000001
#define SDDL_VALID_SACL 0x00000002
//
// This structure is used to do some lookups for mapping ACES
//
typedef struct _STRSD_KEY_LOOKUP {
PWSTR Key; ULONG KeyLen; ULONG Value; ULONG ValidityFlags;
} STRSD_KEY_LOOKUP, *PSTRSD_KEY_LOOKUP;
typedef enum _STRSD_SID_TYPE { ST_DOMAIN_RELATIVE = 0, ST_WORLD, ST_LOCALSY, ST_LOCAL, ST_CREATOR, ST_NTAUTH, ST_BUILTIN, ST_ROOT_DOMAIN_RELATIVE } STRSD_SID_TYPE;
//
// This structure is used to map account monikers to sids
//
typedef struct _STRSD_SID_LOOKUP {
BOOLEAN Valid; WCHAR Key[SDDL_ALIAS_SIZE+2]; ULONG KeyLen; PSID Sid; ULONG Rid; STRSD_SID_TYPE SidType; DWORD SidBuff[ sizeof( SID ) / sizeof( DWORD ) + 5]; } STRSD_SID_LOOKUP, *PSTRSD_SID_LOOKUP;
//
// Globally defined sids
//
/* JINHUANG: not used anywhere
DWORD PersonalSelfBuiltSid[sizeof(SID)/sizeof(DWORD) + 2]; DWORD AuthUserBuiltSid[sizeof(SID)/sizeof(DWORD) + 2]; DWORD CreatorOwnerBuiltSid[sizeof(SID)/sizeof(DWORD) + 2]; DWORD CreatorGroupBuiltSid[sizeof(SID)/sizeof(DWORD) + 2]; PSID PersonalSelfSid = (PSID)PersonalSelfBuiltSid; PSID AuthUserSid = (PSID)AuthUserBuiltSid; PSID CreatorOwnerSid = (PSID)CreatorOwnerBuiltSid; PSID CreatorGroupSid = (PSID)CreatorGroupBuiltSid; */
CRITICAL_SECTION SddlSidLookupCritical; static DWORD SidTableReinitializeInstance=0;
// JINHUANG 3/26 BVT break for dcpromo
//
// Some of the Valid fields were preset to TRUE with NULL Sid field. The SidLookup
// table initialization is stopped if Status is not SUCCESS. So if error occurs,
// for example, no domain info as in dcpromo, other SIDs will not be initialized
// but the Valid fields are set to TRUE (with NULL SIDs).
//
// changes: 1) preset Valid field to FALSE all all lookups and set the Valid to TRUE if
// the SID is really initialized
// 2) do not stop the initialization process if an error occurs
// if the Valid field is already TRUE (already initialized), skip the row
//
static STRSD_SID_LOOKUP SidLookup[] = { { FALSE, SDDL_DOMAIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_DOMAIN_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_GUESTS, SDDL_LEN_TAG( SDDL_DOMAIN_GUESTS ), NULL, DOMAIN_GROUP_RID_GUESTS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_USERS, SDDL_LEN_TAG( SDDL_DOMAIN_USERS ), NULL, DOMAIN_GROUP_RID_USERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_DOMAIN_DOMAIN_CONTROLLERS ), NULL, DOMAIN_GROUP_RID_CONTROLLERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_COMPUTERS, SDDL_LEN_TAG( SDDL_DOMAIN_COMPUTERS ), NULL, DOMAIN_GROUP_RID_COMPUTERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_SCHEMA_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }, // should be root domain only ST_DOMAIN_RELATIVE,
{ FALSE, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ), NULL, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }, // root domain only
{ FALSE, SDDL_CERT_SERV_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_CERT_SERV_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_CERT_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_ACCOUNT_OPERATORS, SDDL_LEN_TAG( SDDL_ACCOUNT_OPERATORS ), NULL, DOMAIN_ALIAS_RID_ACCOUNT_OPS, ST_BUILTIN, 0 }, { FALSE, SDDL_BACKUP_OPERATORS, SDDL_LEN_TAG( SDDL_BACKUP_OPERATORS ), NULL, DOMAIN_ALIAS_RID_BACKUP_OPS, ST_BUILTIN, 0 }, { FALSE, SDDL_PRINTER_OPERATORS, SDDL_LEN_TAG( SDDL_PRINTER_OPERATORS ), NULL, DOMAIN_ALIAS_RID_PRINT_OPS, ST_BUILTIN, 0 }, { FALSE, SDDL_SERVER_OPERATORS, SDDL_LEN_TAG( SDDL_SERVER_OPERATORS ), NULL, DOMAIN_ALIAS_RID_SYSTEM_OPS, ST_BUILTIN, 0 }, { FALSE, SDDL_REPLICATOR, SDDL_LEN_TAG( SDDL_REPLICATOR ), NULL, DOMAIN_ALIAS_RID_REPLICATOR, ST_BUILTIN, 0 }, { FALSE, SDDL_RAS_SERVERS, SDDL_LEN_TAG( SDDL_RAS_SERVERS ), NULL, DOMAIN_ALIAS_RID_RAS_SERVERS, ST_DOMAIN_RELATIVE, 0 }, // ST_LOCAL
{ FALSE, SDDL_AUTHENTICATED_USERS, SDDL_LEN_TAG( SDDL_AUTHENTICATED_USERS ), NULL, SECURITY_AUTHENTICATED_USER_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_PERSONAL_SELF, SDDL_LEN_TAG( SDDL_PERSONAL_SELF ), NULL, SECURITY_PRINCIPAL_SELF_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_CREATOR_OWNER, SDDL_LEN_TAG( SDDL_CREATOR_OWNER ), NULL, SECURITY_CREATOR_OWNER_RID, ST_CREATOR, 0 }, { FALSE, SDDL_CREATOR_GROUP, SDDL_LEN_TAG( SDDL_CREATOR_GROUP ), NULL, SECURITY_CREATOR_GROUP_RID, ST_CREATOR, 0 }, { FALSE, SDDL_LOCAL_SYSTEM, SDDL_LEN_TAG( SDDL_LOCAL_SYSTEM ), NULL, SECURITY_LOCAL_SYSTEM_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_INTERACTIVE, SDDL_LEN_TAG( SDDL_INTERACTIVE ), NULL, SECURITY_INTERACTIVE_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_NETWORK, SDDL_LEN_TAG( SDDL_NETWORK ), NULL, SECURITY_NETWORK_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_SERVICE, SDDL_LEN_TAG( SDDL_SERVICE ), NULL, SECURITY_SERVICE_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_ENTERPRISE_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_ENTERPRISE_DOMAIN_CONTROLLERS ), NULL, SECURITY_SERVER_LOGON_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_RESTRICTED_CODE, SDDL_LEN_TAG( SDDL_RESTRICTED_CODE ), NULL, SECURITY_RESTRICTED_CODE_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_ANONYMOUS, SDDL_LEN_TAG( SDDL_ANONYMOUS ), NULL, SECURITY_ANONYMOUS_LOGON_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_LOCAL_ADMIN, SDDL_LEN_TAG( SDDL_LOCAL_ADMIN ), NULL, DOMAIN_USER_RID_ADMIN, ST_LOCAL, 0 }, { FALSE, SDDL_LOCAL_GUEST, SDDL_LEN_TAG( SDDL_LOCAL_GUEST ), NULL, DOMAIN_USER_RID_GUEST, ST_LOCAL, 0 }, { FALSE, SDDL_BUILTIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_BUILTIN_ADMINISTRATORS ), NULL, DOMAIN_ALIAS_RID_ADMINS, ST_BUILTIN, 0 }, { FALSE, SDDL_BUILTIN_GUESTS, SDDL_LEN_TAG( SDDL_BUILTIN_GUESTS ), NULL, DOMAIN_ALIAS_RID_GUESTS, ST_BUILTIN, 0 }, { FALSE, SDDL_BUILTIN_USERS, SDDL_LEN_TAG( SDDL_BUILTIN_USERS ), NULL, DOMAIN_ALIAS_RID_USERS, ST_BUILTIN, 0 }, { FALSE, SDDL_POWER_USERS, SDDL_LEN_TAG( SDDL_POWER_USERS ), NULL, DOMAIN_ALIAS_RID_POWER_USERS, ST_BUILTIN, 0 }, { FALSE, SDDL_EVERYONE, SDDL_LEN_TAG( SDDL_EVERYONE ), NULL, SECURITY_WORLD_RID, ST_WORLD, 0 }, { FALSE, SDDL_GROUP_POLICY_ADMINS, SDDL_LEN_TAG( SDDL_GROUP_POLICY_ADMINS ), NULL, DOMAIN_GROUP_RID_POLICY_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_ALIAS_PREW2KCOMPACC, SDDL_LEN_TAG( SDDL_ALIAS_PREW2KCOMPACC ), NULL, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS, ST_BUILTIN, 0 }, { FALSE, SDDL_LOCAL_SERVICE, SDDL_LEN_TAG( SDDL_LOCAL_SERVICE ), NULL, SECURITY_LOCAL_SERVICE_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_NETWORK_SERVICE, SDDL_LEN_TAG( SDDL_NETWORK_SERVICE ), NULL, SECURITY_NETWORK_SERVICE_RID, ST_NTAUTH, 0 }, { FALSE, SDDL_REMOTE_DESKTOP, SDDL_LEN_TAG( SDDL_REMOTE_DESKTOP ), NULL, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS, ST_BUILTIN, 0 }, { FALSE, SDDL_NETWORK_CONFIGURATION_OPS, SDDL_LEN_TAG( SDDL_NETWORK_CONFIGURATION_OPS ), NULL, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS, ST_BUILTIN, 0 }, { FALSE, SDDL_PERFMON_USERS, SDDL_LEN_TAG( SDDL_PERFMON_USERS ), NULL, DOMAIN_ALIAS_RID_MONITORING_USERS, ST_BUILTIN, 0 }, { FALSE, SDDL_PERFLOG_USERS, SDDL_LEN_TAG( SDDL_PERFLOG_USERS ), NULL, DOMAIN_ALIAS_RID_LOGGING_USERS, ST_BUILTIN, 0 } };
STRSD_SID_LOOKUP SidLookupDomOrRootDomRelative[] = { { FALSE, SDDL_DOMAIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_DOMAIN_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_GUESTS, SDDL_LEN_TAG( SDDL_DOMAIN_GUESTS ), NULL, DOMAIN_GROUP_RID_GUESTS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_USERS, SDDL_LEN_TAG( SDDL_DOMAIN_USERS ), NULL, DOMAIN_GROUP_RID_USERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_DOMAIN_DOMAIN_CONTROLLERS ), NULL, DOMAIN_GROUP_RID_CONTROLLERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_DOMAIN_COMPUTERS, SDDL_LEN_TAG( SDDL_DOMAIN_COMPUTERS ), NULL, DOMAIN_GROUP_RID_COMPUTERS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_CERT_SERV_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_CERT_SERV_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_CERT_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_RAS_SERVERS, SDDL_LEN_TAG( SDDL_RAS_SERVERS ), NULL, DOMAIN_ALIAS_RID_RAS_SERVERS, ST_DOMAIN_RELATIVE, 0 }, // ST_LOCAL
{ FALSE, SDDL_GROUP_POLICY_ADMINS, SDDL_LEN_TAG( SDDL_GROUP_POLICY_ADMINS ), NULL, DOMAIN_GROUP_RID_POLICY_ADMINS, ST_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ), NULL, DOMAIN_GROUP_RID_SCHEMA_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }, { FALSE, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ), NULL, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 } };
static DWORD RootDomSidBuf[sizeof(SID)/sizeof(DWORD)+5]; static BOOL RootDomInited=FALSE;
#define STRSD_REINITIALIZE_ENTER 1
#define STRSD_REINITIALIZE_LEAVE 2
BOOLEAN InitializeSidLookupTable( IN BYTE InitFlag );
//
// Control Lookup table
//
static STRSD_KEY_LOOKUP ControlLookup[] = { { SDDL_PROTECTED, SDDL_LEN_TAG( SDDL_PROTECTED ), SE_DACL_PROTECTED, SDDL_VALID_DACL }, { SDDL_AUTO_INHERIT_REQ, SDDL_LEN_TAG( SDDL_AUTO_INHERIT_REQ ), SE_DACL_AUTO_INHERIT_REQ, SDDL_VALID_DACL }, { SDDL_AUTO_INHERITED, SDDL_LEN_TAG( SDDL_AUTO_INHERITED ), SE_DACL_AUTO_INHERITED, SDDL_VALID_DACL }, { SDDL_PROTECTED, SDDL_LEN_TAG( SDDL_PROTECTED ), SE_SACL_PROTECTED, SDDL_VALID_SACL }, { SDDL_AUTO_INHERIT_REQ, SDDL_LEN_TAG( SDDL_AUTO_INHERIT_REQ ), SE_SACL_AUTO_INHERIT_REQ, SDDL_VALID_SACL }, { SDDL_AUTO_INHERITED, SDDL_LEN_TAG( SDDL_AUTO_INHERITED ), SE_SACL_AUTO_INHERITED, SDDL_VALID_SACL } };
//
// Local prototypes
//
BOOL LocalConvertStringSidToSid( IN PWSTR String, OUT PSID *SID, OUT PWSTR *End );
PSTRSD_SID_LOOKUP LookupSidInTable( IN PWSTR String, OPTIONAL IN PSID Sid OPTIONAL, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain, OUT PVOID *pSASid );
DWORD LocalGetSidForString( IN PWSTR String, OUT PSID *SID, OUT PWSTR *End, OUT PBOOLEAN FreeSid, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain );
PSTRSD_KEY_LOOKUP LookupAccessMaskInTable( IN PWSTR String, OPTIONAL IN ULONG AccessMask, OPTIONAL IN ULONG LookupFlags );
PSTRSD_KEY_LOOKUP LookupAceTypeInTable( IN PWSTR String, OPTIONAL IN ULONG AceType, OPTIONAL IN ULONG LookupFlags );
PSTRSD_KEY_LOOKUP LookupAceFlagsInTable( IN PWSTR String, OPTIONAL IN ULONG AceFlags OPTIONAL, IN ULONG LookupFlags );
DWORD LocalGetStringForSid( IN PSID Sid, OUT PWSTR *String, IN PSID RootDomainSid OPTIONAL );
DWORD LocalGetStringForControl( IN SECURITY_DESCRIPTOR_CONTROL ControlCode, IN ULONG LookupFlags, OUT PWSTR *ControlString );
DWORD LocalGetSDControlForString ( IN PWSTR AclString, IN ULONG LookupFlags, OUT SECURITY_DESCRIPTOR_CONTROL *pControl, OUT PWSTR *End );
DWORD LocalGetAclForString ( IN PWSTR AclString, IN BOOLEAN ConvertAsDacl, OUT PACL *Acl, OUT PWSTR *End, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain );
DWORD LocalConvertAclToString( IN PACL Acl, IN BOOLEAN AclPresent, IN BOOLEAN ConvertAsDacl, OUT PWSTR *AclString, OUT PDWORD AclStringSize, IN PSID RootDomainSid OPTIONAL );
DWORD LocalConvertSDToStringSD_Rev1( IN PSID RootDomainSid OPTIONAL, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN SECURITY_INFORMATION SecurityInformation, OUT LPWSTR *StringSecurityDescriptor, OUT PULONG StringSecurityDescriptorLen OPTIONAL );
DWORD LocalConvertStringSDToSD_Rev1( IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN BOOLEAN DefaultToDomain, IN LPCWSTR StringSecurityDescriptor, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL );
BOOL SddlpGetRootDomainSid(void);
//
// Exported functions
//
BOOL APIENTRY ConvertSidToStringSidA( IN PSID Sid, OUT LPSTR *StringSid ) /*++
Routine Description:
ANSI thunk to ConvertSidToStringSidW
--*/ { LPWSTR StringSidW = NULL; ULONG AnsiLen, WideLen; BOOL ReturnValue;
if ( NULL == StringSid ) { //
// invalid parameter
//
SetLastError( ERROR_INVALID_PARAMETER ); return(FALSE); }
ReturnValue = ConvertSidToStringSidW( Sid, &StringSidW );
if ( ReturnValue ) {
WideLen = wcslen( StringSidW ) + 1;
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSidW, WideLen, *StringSid, 0, NULL, NULL );
if ( AnsiLen != 0 ) {
*StringSid = LocalAlloc( LMEM_FIXED, AnsiLen );
if ( *StringSid == NULL ) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); ReturnValue = FALSE;
} else {
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSidW, WideLen, *StringSid, AnsiLen, NULL, NULL ); ASSERT( AnsiLen != 0 );
if ( AnsiLen == 0 ) {
ReturnValue = FALSE; //
// jinhuang: failed, free the buffer
//
LocalFree(*StringSid); *StringSid = NULL; } }
} else {
ReturnValue = FALSE; }
}
//
// jinhuang: free the wide buffer
//
if ( StringSidW ) { LocalFree(StringSidW); }
if ( ReturnValue ) { SetLastError(ERROR_SUCCESS); }
return( ReturnValue );
}
BOOL APIENTRY ConvertSidToStringSidW( IN PSID Sid, OUT LPWSTR *StringSid ) /*++
Routine Description:
This routine converts a SID into a string representation of a SID, suitable for framing or display
Arguments:
Sid - SID to be converted.
StringSid - Where the converted SID is returned. Allocated via LocalAlloc and needs to be freed via LocalFree.
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
--*/ { NTSTATUS Status; UNICODE_STRING UnicodeStringSid;
if ( NULL == Sid || NULL == StringSid ) { //
// invalid parameter
//
SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); }
//
// Convert using the Rtl functions
//
Status = RtlConvertSidToUnicodeString( &UnicodeStringSid, Sid, TRUE );
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status ); return( FALSE ); }
//
// Convert it to the proper allocator
//
*StringSid = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, UnicodeStringSid.Length + sizeof( WCHAR ) );
if ( *StringSid == NULL ) {
RtlFreeUnicodeString( &UnicodeStringSid );
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return( FALSE );
}
RtlCopyMemory( *StringSid, UnicodeStringSid.Buffer, UnicodeStringSid.Length ); RtlFreeUnicodeString( &UnicodeStringSid );
SetLastError(ERROR_SUCCESS); return( TRUE ); }
BOOL APIENTRY ConvertStringSidToSidA( IN LPCSTR StringSid, OUT PSID *Sid ) /*++
Routine Description:
ANSI thunk to ConvertStringSidToSidW
--*/ { UNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; BOOL Result;
if ( NULL == StringSid || NULL == Sid ) {
SetLastError( ERROR_INVALID_PARAMETER ); return(FALSE); }
RtlInitAnsiString( &AnsiString, StringSid );
Status = SddlpAnsiStringToUnicodeString(&Unicode, &AnsiString);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status );
return FALSE;
}
Result = ConvertStringSidToSidW( ( LPCWSTR )Unicode.Buffer, Sid );
LocalFree( Unicode.Buffer );
if ( Result ) { SetLastError(ERROR_SUCCESS); }
return( Result ); }
BOOL APIENTRY ConvertStringSidToSidW( IN LPCWSTR StringSid, OUT PSID *Sid ) /*++
Routine Description:
This routine converts a stringized SID into a valid, functional SID
Arguments:
StringSid - SID to be converted.
Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should be free via LocalFree.
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
ERROR_INVALID_PARAMETER - A NULL name was given
ERROR_INVALID_SID - The format of the given sid was incorrect
--*/ { PWSTR End = NULL; BOOL ReturnValue = FALSE; PSTRSD_SID_LOOKUP MatchedEntry=NULL; PSID pSASid=NULL; ULONG Len=0; DWORD SaveCode=0; DWORD Err=0;
if ( StringSid == NULL || Sid == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
} else {
ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
if ( ReturnValue == TRUE ) {
if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
SetLastError( ERROR_INVALID_SID ); LocalFree( *Sid ); *Sid = FALSE; ReturnValue = FALSE;
} else { SetLastError(ERROR_SUCCESS); }
} else {
SaveCode = GetLastError();
//
// lookup in the SidLookup table to see if it's pre-defined
//
MatchedEntry = LookupSidInTable( (PWSTR)StringSid, NULL, NULL, NULL, NULL, FALSE, (PVOID *)&pSASid);
if ( MatchedEntry && MatchedEntry->Sid ) {
//
// find it in the table, check if the input string is valid
//
if ( wcslen( (PWSTR)StringSid ) != MatchedEntry->KeyLen ) {
//
// the total string length doesn't match the table define
//
SetLastError(ERROR_INVALID_SID);
} else {
//
// matched! now copy it to the output buffer
//
Len = RtlLengthSid ( MatchedEntry->Sid );
*Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Len );
if ( *Sid == NULL ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
} else {
Err = RtlNtStatusToDosError(RtlCopySid ( Len, *Sid, MatchedEntry->Sid ) );
if ( ERROR_SUCCESS == Err ) {
ReturnValue = TRUE;
} else {
LocalFree(*Sid); *Sid = NULL; }
SetLastError(Err);
} }
} else if ( pSASid && wcslen((PWSTR)StringSid) == SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ) ) { //
// this is schema admin SID
//
*Sid = pSASid; pSASid = NULL;
ReturnValue = TRUE;
SetLastError(ERROR_SUCCESS);
} else { //
// reset last error
//
SetLastError(SaveCode); } }
if ( pSASid ) { LocalFree(pSASid); } }
return( ReturnValue );
}
BOOL APIENTRY ConvertStringSecurityDescriptorToSecurityDescriptorA( IN LPCSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) /*++
Routine Description:
ANSI thunk to ConvertStringSecurityDescriptorToSecurityDescriptorW
--*/ { UNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; BOOL Result;
if ( NULL == StringSecurityDescriptor || NULL == SecurityDescriptor ) {
SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); }
RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
Status = SddlpAnsiStringToUnicodeString(&Unicode, &AnsiString);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status );
return FALSE;
}
Result = ConvertStringSecurityDescriptorToSecurityDescriptorW( ( LPCWSTR )Unicode.Buffer, StringSDRevision, SecurityDescriptor, SecurityDescriptorSize);
LocalFree( Unicode.Buffer );
if ( Result ) { SetLastError(ERROR_SUCCESS); }
return( Result ); }
BOOL APIENTRY ConvertStringSecurityDescriptorToSecurityDescriptorW( IN LPCWSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) /*++
Routine Description:
This routine converts a stringized Security descriptor into a valid, functional security descriptor
Ex: SD:[O:xyz][G:xyz][D: (Ace1)(Ace2)][S: (Ace3)(Ace4)] where some Ace is (OA;CIIO; DS_READ; OT: abc; IOT: abc; SID: xyz)
So a possible Security descriptor may be (as all one long string):
L"O:AOG:DAD:(A;IO;RPRWXRCWDWO;;;S-1-0-0)(OA;CI;RWX;af110080-1b13-11d0-af10-0020afd3606c;" L"a153d9e0-1b13-11d0-af10-0020afd3606c;AUS)(A;SAFA;0x7800003F;;;DA)(OA;FA;X;" L"954378e0-1b13-11d0-af10-0020afd3606c;880b12a0-1b13-11d0-af10-0020afd3606c;PO)"
would build a security descriptor:
Revision: 0x1 Sbz1: 0x0 Control: 0x8014 Owner: S-1-5-32-548
Group:S-1-5-32-544
Dacl: Revision: 4 AceCount: 2 InUse: 84 Free: 52 Flags: 0 Ace 0: Type: 0 Flags: 0x1 Size: 0x14 Mask: 0xe00e0010 S-1-0-0
Ace 1: Type: 5 Flags: 0x2 Size: 0x38 Mask: 0xe0000000 af110080-1b13-11d0-af100020afd3606c a153d9e0-1b13-11d0-af100020afd3606c S-1-5-11
sacl: Revision: 4 AceCount: 2 InUse: 92 Free: 44 Flags: 0 Ace 0: Type: 2 Flags: 0xc0 Size: 0x18 Mask: 0xe0000000 S-1-5-32-544
Ace 1: Type: 7 Flags: 0x80 Size: 0x3c Mask: 0x20000000 954378e0-1b13-11d0-af100020afd3606c 880b12a0-1b13-11d0-af100020afd3606c S-1-5-32-550 Arguments:
StringSecurityDescriptor - Stringized security descriptor to be converted.
StringSDRevision - String revision of the input string SD
SecurityDescriptor - Where the converted SD is returned. Buffer is allocated via LocalAlloc and should be free via LocalFree. The returned security descriptor is always self relative
SecurityDescriptorSize - OPTIONAL. If non-NULL, the size of the converted security descriptor is returned here.
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
ERROR_UNKNOWN_REVISION - An unsupported revision was given
--*/ { DWORD Err = ERROR_SUCCESS;
//
// Little elementary parameter checking...
//
if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) {
Err = ERROR_INVALID_PARAMETER;
} else {
switch ( StringSDRevision ) { case SDDL_REVISION_1:
Err = LocalConvertStringSDToSD_Rev1( NULL, // no root domain sid is provided
NULL, // no domain sid is provided for this API
FALSE, //TRUE, do not default to domain for EA/SA
StringSecurityDescriptor, SecurityDescriptor, SecurityDescriptorSize); break;
default:
Err = ERROR_UNKNOWN_REVISION; break; }
}
SetLastError( Err );
return( Err == ERROR_SUCCESS ); }
BOOL APIENTRY ConvertSecurityDescriptorToStringSecurityDescriptorA( IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN DWORD RequestedStringSDRevision, IN SECURITY_INFORMATION SecurityInformation, OUT LPSTR *StringSecurityDescriptor, OUT PULONG StringSecurityDescriptorLen OPTIONAL ) /*++
Routine Description:
ANSI thunk to ConvertSecurityDescriptorToStringSecurityDescriptorW
--*/ { LPWSTR StringSecurityDescriptorW = NULL; ULONG AnsiLen, WideLen = 0; BOOL ReturnValue ;
if ( StringSecurityDescriptor == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); }
ReturnValue = ConvertSecurityDescriptorToStringSecurityDescriptorW( SecurityDescriptor, RequestedStringSDRevision, SecurityInformation, &StringSecurityDescriptorW, &WideLen );
if ( ReturnValue ) {
// jinhuang: WindeLen is returned from previous call
// WideLen = wcslen( StringSecurityDescriptorW ) + 1;
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSecurityDescriptorW, WideLen + 1, *StringSecurityDescriptor, 0, NULL, NULL );
if ( AnsiLen != 0 ) {
*StringSecurityDescriptor = LocalAlloc( LMEM_FIXED, AnsiLen );
if ( *StringSecurityDescriptor == NULL ) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); ReturnValue = FALSE;
} else {
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSecurityDescriptorW, WideLen + 1, *StringSecurityDescriptor, AnsiLen, NULL, NULL ); ASSERT( AnsiLen != 0 );
if ( AnsiLen == 0 ) {
LocalFree(*StringSecurityDescriptor); *StringSecurityDescriptor = NULL;
ReturnValue = FALSE; }
//
// jinhuang
// output the length (optional)
//
if ( StringSecurityDescriptorLen ) { *StringSecurityDescriptorLen = AnsiLen; }
}
} else {
ReturnValue = FALSE; }
//
// jinhuang
// StringSecurityDescriptorW should be freed
//
LocalFree(StringSecurityDescriptorW);
}
if ( ReturnValue ) { SetLastError(ERROR_SUCCESS); }
return( ReturnValue ); }
BOOL APIENTRY ConvertSecurityDescriptorToStringSecurityDescriptorW( IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN DWORD RequestedStringSDRevision, IN SECURITY_INFORMATION SecurityInformation, OUT LPWSTR *StringSecurityDescriptor, OUT PULONG StringSecurityDescriptorLen OPTIONAL ) /*++
Routine Description:
This routine converts a security descriptor into a string version persuant to SDDL definition
Arguments:
SecurityDescriptor - Security Descriptor to be converted.
RequestedStringSDRevision - Requested revision of the output string security descriptor
SecurityInformation - security information of which to be converted
StringSecurityDescriptor - Where the converted SD is returned. Buffer is allocated via LocalAlloc and should be free via LocalFree.
StringSecurityDescriptorLen - the optional length of the converted SD
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
ERROR_UNKNOWN_REVISION - An unsupported revision was given
--*/ { DWORD Err = ERROR_SUCCESS;
//
// A little parameter checking...
//
if ( (SecurityDescriptor == NULL || SecurityInformation == 0) && StringSecurityDescriptor ) { *StringSecurityDescriptor = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof( WCHAR ) );
if (*StringSecurityDescriptor) { (*StringSecurityDescriptor)[0] = L'\0';
if (StringSecurityDescriptorLen) {
*StringSecurityDescriptorLen = 0; }
}
else { Err = ERROR_NOT_ENOUGH_MEMORY;
}
SetLastError( Err );
return( Err == ERROR_SUCCESS );
} if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL || SecurityInformation == 0 ) {
Err = ERROR_INVALID_PARAMETER;
} else {
switch ( RequestedStringSDRevision ) { case SDDL_REVISION_1:
Err = LocalConvertSDToStringSD_Rev1( NULL, // root domain sid is not privided
SecurityDescriptor, SecurityInformation, StringSecurityDescriptor, StringSecurityDescriptorLen ); break;
default: Err = ERROR_UNKNOWN_REVISION; break; }
}
SetLastError( Err );
return( Err == ERROR_SUCCESS); }
//
// Private functions
//
BOOL LocalConvertStringSidToSid ( IN PWSTR StringSid, OUT PSID *Sid, OUT PWSTR *End ) /*++
Routine Description:
This routine will convert a string representation of a SID back into a sid. The expected format of the string is: "S-1-5-32-549" If a string in a different format or an incorrect or incomplete string is given, the operation is failed.
The returned sid must be free via a call to LocalFree
Arguments:
StringSid - The string to be converted
Sid - Where the created SID is to be returned
End - Where in the string we stopped processing
Return Value:
TRUE - Success.
FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
ERROR_SUCCESS indicates success
ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid failed ERROR_INVALID_SID indicates that the given string did not represent a sid
--*/ { DWORD Err = ERROR_SUCCESS; UCHAR Revision, Subs; SID_IDENTIFIER_AUTHORITY IDAuth; PULONG SubAuth = NULL; PWSTR CurrEnd, Curr, Next;
ULONG Index; INT gBase=10; INT lBase=10; ULONGLONG Auto; ULONG ulRev; //
// ID authority is defined to be a 48 bit value
//
const ULONGLONG ullMaxIdAuthority = 0x0000FFFFFFFFFFFF;
WCHAR wchSidString[SDDL_SID_STRING_SIZE]; PWSTR pwszHeapSidStr = NULL;
if ( NULL == StringSid || NULL == Sid || NULL == End ) {
SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE );
}
// if ( wcslen( StringSid ) < 2 || ( *StringSid != L'S' && *( StringSid + 1 ) != L'-' ) ) {
//
// no need to check length because StringSid is NULL
// and if the first char is NULL, it won't access the second char
//
if ( (*StringSid != L'S' && *StringSid != L's') || *( StringSid + 1 ) != L'-' ) { //
// string sid should always start with S-
//
SetLastError( ERROR_INVALID_SID ); return( FALSE ); }
Curr = StringSid + 2;
if ( (*Curr == L'0') && ( *(Curr+1) == L'x' || *(Curr+1) == L'X' ) ) {
gBase = 16; }
ulRev = wcstoul( Curr, &CurrEnd, gBase );
if (ulRev > 0xFF || CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) { //
// no revision is provided, or invalid delimeter
//
SetLastError( ERROR_INVALID_SID ); return( FALSE ); }
Revision = (UCHAR)ulRev;
Curr = CurrEnd + 1;
//
// Count the number of characters in the indentifer authority...
//
Next = wcschr( Curr, L'-' ); if (Next == NULL || Next == Curr) { //
// no identifier authority
//
SetLastError( ERROR_INVALID_SID ); return( FALSE ); }
/*
Length = 6 doesn't mean each digit is a id authority value, could be 0x...
if ( Next != NULL && (Next - Curr == 6) ) {
for ( Index = 0; Index < 6; Index++ ) {
// IDAuth.Value[Index] = (UCHAR)Next[Index]; what is this ???
IDAuth.Value[Index] = (BYTE) (Curr[Index]-L'0'); }
Curr +=6;
} else { */ if ( (*Curr == L'0') && ( *(Curr+1) == L'x' || *(Curr+1) == L'X' ) ) {
lBase = 16; } else { lBase = gBase; }
Auto = _wcstoui64( Curr, &CurrEnd, lBase );
if (Auto > ullMaxIdAuthority) { //
// Must be overflow
//
SetLastError( ERROR_INVALID_SID ); return FALSE; }
if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) { //
// no revision is provided, or invalid delimeter
//
SetLastError( ERROR_INVALID_SID ); return( FALSE ); }
IDAuth.Value[5] = ( UCHAR )Auto & 0xFF; IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF ); IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF ); IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF ); IDAuth.Value[1] = ( UCHAR )(( Auto >> 32 ) & 0xFF ); IDAuth.Value[0] = ( UCHAR )(( Auto >> 40 ) & 0xFF ); Curr = CurrEnd; // }
//
// Now, count the number of sub auths, at least one sub auth is required
//
Subs = 0; Next = Curr;
//
// We'll have to count our sub authoritys one character at a time,
// since there are several deliminators that we can have...
//
while ( Next ) {
if ( *Next == L'-' && *(Next-1) != L'-') {
//
// do not allow two continuous '-'s
// We've found one!
//
Subs++;
if ( (*(Next+1) == L'0') && ( *(Next+2) == L'x' || *(Next+2) == L'X' ) ) { //
// this is hex indicator
//
Next += 2;
}
} else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' || *Next == SDDL_ACE_ENDC || *Next == L' ' || ( *(Next+1) == SDDL_DELIMINATORC && (*Next == L'G' || *Next == L'O' || *Next == L'S')) ) { //
// space is a terminator too
//
if ( *( Next - 1 ) == L'-' ) { //
// shouldn't allow a SID terminated with '-'
//
Err = ERROR_INVALID_SID; Next--;
} else { Subs++; }
*End = Next; break;
} else if ( !iswxdigit( *Next ) ) {
Err = ERROR_INVALID_SID; *End = Next; // Subs++;
break;
} else {
//
// Note: SID is also used as a owner or group
//
// Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
// if the current character is a character we care about and the next one is a
// delminiator, we'll quit
//
if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
//
// We need to make a copy this of SID string from Curr to Next
//
LPCWSTR pwszStart = Curr; //
// For majority, the our stack variable's size is large enough.
// This will perform much better.
//
if ( (Next - pwszStart) < SDDL_SID_STRING_SIZE ) { Curr = wchSidString; } else { pwszHeapSidStr = (PWSTR)LocalAlloc(LPTR, ((Next - pwszStart) + 1) * sizeof(WCHAR)); if ( NULL == pwszHeapSidStr ) { Err = ERROR_NOT_ENOUGH_MEMORY; break; } else { Curr = pwszHeapSidStr; } } //
// Copy the sub-string of the sid and then NULL terminate it
//
memcpy(Curr, pwszStart, (Next - pwszStart) * sizeof(WCHAR)); Curr[(Next - pwszStart)] = L'\0'; *End = Next; Subs++; break; }
}
Next++;
}
if ( Err == ERROR_SUCCESS ) {
if ( Subs != 0 ) Subs--;
if ( Subs != 0 ) {
Curr++;
SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
if ( SubAuth == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
for ( Index = 0; Index < Subs; Index++ ) {
if ( (*Curr == L'0') && ( *(Curr+1) == L'x' || *(Curr+1) == L'X' ) ) {
lBase = 16; } else { lBase = gBase; }
SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
//
// Valid sub-authority ID must end with delimiter L'-', right parentheless, or one
// of the following:
// D:
// S:
// O:
// G:
//
if (CurrEnd != NULL && *CurrEnd != L'\0' && *CurrEnd != SDDL_ACE_ENDC && *CurrEnd != L'-' && ( *(CurrEnd + 1) != SDDL_DELIMINATORC || // because of *CurrEnd != L'\0', we are safe
*CurrEnd != *SDDL_OWNER && *CurrEnd != *SDDL_GROUP && *CurrEnd != *SDDL_DACL && *CurrEnd != *SDDL_SACL ) ) { Err = ERROR_INVALID_SID; break; } else { Curr = CurrEnd + 1; } } }
} else {
Err = ERROR_INVALID_SID; } }
//
// Now, create the SID
//
if ( Err == ERROR_SUCCESS ) {
*Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof( SID ) + Subs * sizeof( ULONG ) );
if ( *Sid == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
PISID ISid = ( PISID )*Sid; ISid->Revision = Revision; ISid->SubAuthorityCount = Subs; RtlCopyMemory( &( ISid->IdentifierAuthority ), &IDAuth, sizeof( SID_IDENTIFIER_AUTHORITY ) ); RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) ); } }
LocalFree( SubAuth );
if ( NULL != pwszHeapSidStr ) {
LocalFree(pwszHeapSidStr); }
SetLastError( Err );
return( Err == ERROR_SUCCESS ); }
PSTRSD_SID_LOOKUP LookupSidInTable( IN PWSTR String OPTIONAL, IN PSID Sid OPTIONAL, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain, IN PVOID *pSASid ) /*++
Routine Description:
This routine will determine if the given sid or string sid exists in the lookup table.
A pointer to the matching static lookup entry is returned.
Arguments:
String - The string to be looked up
Sid - The sid to be looked up.
Return Value:
Lookup table entry if found
NULL if not found
--*/ { BOOLEAN LookupSid = FALSE; DWORD i, SidCount = sizeof( SidLookup ) / sizeof( STRSD_SID_LOOKUP ); PSTRSD_SID_LOOKUP MatchedEntry = NULL; DWORD DomainAdminIndex;
BOOL InitRootDomain; ULONG Rid; BOOL bIsSA = FALSE;
if ( String == NULL && Sid == NULL ) { //
// JINHUANG: if both string and sid are NULL
// just return NULL
//
return((PSTRSD_SID_LOOKUP)NULL); }
*pSASid = NULL;
InitRootDomain = FALSE; DomainAdminIndex = SidCount;
if ( String == NULL ) { //
// lookup on the Sid
//
LookupSid = TRUE;
//
// check if the RID is for Enterprise Admins
//
Rid = *( RtlSubAuthoritySid( Sid, *( RtlSubAuthorityCountSid(Sid) ) - 1 ) );
if ( DOMAIN_GROUP_RID_ENTERPRISE_ADMINS == Rid || DOMAIN_GROUP_RID_SCHEMA_ADMINS == Rid ) {
InitRootDomain = TRUE; if ( DOMAIN_GROUP_RID_SCHEMA_ADMINS == Rid ) { bIsSA = TRUE; } }
} else {
if ( _wcsnicmp( String, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ) ) == 0 ) { //
// Enterprise admins string is requested
//
InitRootDomain = TRUE; } else if ( _wcsnicmp( String, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ) ) == 0 ) { //
// schema admin is requested
//
InitRootDomain = TRUE; bIsSA = TRUE; } }
//
// the new API is the caller iff DomainSid != NULL
// on demand, initialize domain relative dynamic table for new API ()
//
if ( DomainSid ) {
//
// in this search, we will deal with the per thread table and not the global table
// in actuality, this per thread table is a proper subset of the global table
//
for ( i = 0; i < sizeof(SidLookupDomOrRootDomRelative)/sizeof(STRSD_SID_LOOKUP); i++ ) {
//
// for performance, only compute SID etc. if names match.
// in case the table is sparse, this heuristic comes in handy
// this doesn't preclude future lookup calls from leveraging useful work done here
//
if ( _wcsnicmp( String, tSidLookupDomOrRootDomRelativeTable[ i ].Key, tSidLookupDomOrRootDomRelativeTable[ i ].KeyLen ) == 0 ) {
if (tSidLookupDomOrRootDomRelativeTable[ i ].Valid == FALSE || tSidLookupDomOrRootDomRelativeTable[ i ].Sid == NULL) {
PSID RootDomainSidOrDomainSid = NULL;
if ( tSidLookupDomOrRootDomRelativeTable[ i ].SidType == ST_DOMAIN_RELATIVE ) RootDomainSidOrDomainSid = DomainSid; else if ( tSidLookupDomOrRootDomRelativeTable[ i ].SidType == ST_ROOT_DOMAIN_RELATIVE && RootDomainSid ) RootDomainSidOrDomainSid = RootDomainSid; else { //
// this will happen when the RootDomainSid is not provided when using the
// new API and so ST_ROOT_DOMAIN_RELATIVE type SIDs will get resolved wrt
// the local m/c's root domain - so we will allow the lookup to continue
// in the normal way
//
break; }
//
// do this for legacy-code reasons
//
tSidLookupDomOrRootDomRelativeTable[ i ].Sid = ( PSID )tSidLookupDomOrRootDomRelativeTable[ i ].SidBuff;
RtlCopyMemory( tSidLookupDomOrRootDomRelativeTable[ i ].Sid, RootDomainSidOrDomainSid, RtlLengthSid( RootDomainSidOrDomainSid ) ); ( ( PISID )( tSidLookupDomOrRootDomRelativeTable[ i ].Sid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( tSidLookupDomOrRootDomRelativeTable[ i ].Sid, *( RtlSubAuthorityCountSid( RootDomainSidOrDomainSid ) ) ) ) = tSidLookupDomOrRootDomRelativeTable[ i ].Rid;
tSidLookupDomOrRootDomRelativeTable[ i ].Valid = TRUE;
}
if (tSidLookupDomOrRootDomRelativeTable[ i ].Valid == TRUE) MatchedEntry = &tSidLookupDomOrRootDomRelativeTable[ i ];
//
// if we get here, we have to return MatchedEntry since we know that:
//
// (a) the new API is the caller (DomainSid != NULL) and
// (b) we are dealing with ST_DOMAIN_RELATIVE or
// ST_ROOT_DOMAIN_RELATIVE type trustees (with RootDomainSid provided)
// (c) there is a match with the trustee name such as "DA" or "EA"
//
return (MatchedEntry);
}
}
}
InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
if ( InitRootDomain && RootDomainSid == NULL && DefaultToDomain == FALSE && ( RootDomInited == FALSE || !RtlValidSid( (PSID)RootDomSidBuf ) ) ) {
//
// get the root domain sid (using ldap calls)
//
SddlpGetRootDomainSid();
}
for ( i = 0; i < SidCount; i++ ) {
//
// if new API and domain relative trustee, skip the entry
// since the global table won't be used in this scenario.
// matches for such entries are taken care of, in the per-thread table above
//
// cannot skip if InitRootDomain == TRUE since SDDL_DOMAIN_ADMINISTRATORS in
// SidLookup[] is potentially matched against, shortly
//
if ( InitRootDomain == FALSE && DomainSid && SidLookup[ i ].SidType == ST_DOMAIN_RELATIVE ) continue;
//
// if this is an entry that has been initialized, skip it
//
if ( SidLookup[ i ].Valid == FALSE || SidLookup[ i ].Sid == NULL ) {
if ( SidLookup[ i ].SidType == ST_ROOT_DOMAIN_RELATIVE && InitRootDomain ) {
if ( RootDomainSid != NULL ) {
EnterCriticalSection(&SddlSidLookupCritical);
RtlCopyMemory( SidLookup[ i ].Sid, RootDomainSid, RtlLengthSid( RootDomainSid ) ); ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( SidLookup[ i ].Sid, *( RtlSubAuthorityCountSid( RootDomainSid ) ) ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE;
LeaveCriticalSection(&SddlSidLookupCritical);
} else if ( DefaultToDomain ) { //
// should default EA to DA and SA to domain relative
//
} else {
if ( RootDomInited && RtlValidSid( (PSID)RootDomSidBuf ) && ( ( SidLookup[ i ].Valid == FALSE ) || ( SidLookup[ i ].Sid == NULL ) ) ) {
EnterCriticalSection(&SddlSidLookupCritical);
RtlCopyMemory( SidLookup[ i ].Sid, (PSID)RootDomSidBuf, RtlLengthSid( (PSID)RootDomSidBuf ) ); ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( SidLookup[ i ].Sid, *( RtlSubAuthorityCountSid( (PSID)RootDomSidBuf ) ) ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE;
LeaveCriticalSection(&SddlSidLookupCritical); }
}
}
if ( SidLookup[ i ].Valid == FALSE || SidLookup[ i ].Sid == NULL ) { continue; } }
if ( LookupSid ) {
if ( RtlEqualSid( Sid, SidLookup[ i ].Sid ) ) {
break; }
} else {
//
// check for the current key first
//
if ( _wcsnicmp( String, SidLookup[i].Key, SidLookup[i].KeyLen ) == 0 ) {
break;
} else if ( InitRootDomain && DefaultToDomain && (RootDomainSid == NULL) ) {
//
// looking for EA/SA, not found them,
// EA needs to default to DA, SA needs to default to domain relative
//
if ( _wcsnicmp( SDDL_DOMAIN_ADMINISTRATORS, SidLookup[i].Key, SidLookup[i].KeyLen ) == 0 ) { DomainAdminIndex = i; // break;
}
} } }
if ( i < SidCount ) {
MatchedEntry = &SidLookup[ i ];
} else if ( InitRootDomain && DefaultToDomain && (RootDomainSid == NULL) && ( DomainAdminIndex < SidCount ) ) {
if ( bIsSA ) { //
// default to domain relative sid
//
if ( LookupSid ) { *pSASid = (PVOID)Sid;
} else if ( SidLookup[ DomainAdminIndex ].Sid ) { //
// allocate buffer for domain relative SA sid
// which means it's only valid on the root domain
//
i = RtlLengthSid( SidLookup[ DomainAdminIndex ].Sid );
*pSASid = (PVOID)LocalAlloc( LMEM_FIXED, i+1 );
if ( *pSASid != NULL ) {
RtlCopyMemory( (PSID)(*pSASid), SidLookup[ DomainAdminIndex ].Sid, i );
// replace the DA rid with SA rid
*( RtlSubAuthoritySid( (PSID)(*pSASid), *( RtlSubAuthorityCountSid( SidLookup[ DomainAdminIndex ].Sid )) - 1) ) = DOMAIN_GROUP_RID_SCHEMA_ADMINS; } }
} else {
//
// default to the domain admin account
//
MatchedEntry = &SidLookup[ DomainAdminIndex ]; } }
InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
return( MatchedEntry ); }
DWORD LocalGetSidForString( IN PWSTR String, OUT PSID *SID, OUT PWSTR *End, OUT PBOOLEAN FreeSid, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain ) /*++
Routine Description:
This routine will determine which sid is an appropriate match for the given string, either as a sid moniker or as a string representation of a sid (ie: "DA or "S-1-0-0" )
The returned sid must be free via a call to LocalFree if the *pFreeSid output parameter is TRUE. If it's FALSE, no additional action needs to be taken
Arguments:
String - The string to be converted
Sid - Where the created SID is to be returned
End - Where in the string we stopped processing
FreeSid - Determines whether the returned SID needs to be freed via a call to LocalFree or not
Return Value:
ERROR_SUCCESS - success
ERROR_NON_MAPPED - An invalid format of the SID was given
--*/ { DWORD Err = ERROR_SUCCESS; PSTRSD_SID_LOOKUP MatchedEntry; PSID pSidSA=NULL;
if ( String == NULL || SID == NULL || End == NULL || FreeSid == NULL ) { return(ERROR_INVALID_PARAMETER); }
//
// Assume we'll return a well known sid
//
*FreeSid = FALSE;
// if ( wcslen( String ) < 2 ) {
// no need to do wcslen (expensive) because we know that String is not NULL
// so just check for the first and second char
if ( *String == L'\0' || *( String +1 ) == L'\0' ) {
return( ERROR_NONE_MAPPED ); }
//
// Set our end of string pointer
//
*End = String + 2;
MatchedEntry = LookupSidInTable( String, NULL, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain, (PVOID *)&pSidSA);
//
// If we didn't find a match, try it as a sid string
//
if ( MatchedEntry == NULL ) {
if ( pSidSA ) { //
// this is schema admin lookup
//
*SID = pSidSA; *FreeSid = TRUE;
} else {
//
// We assumed a known moniker, so we'll have to unset our end of string pointer.
// Also, if it's a not a SID, the Convert routine will return the appropriate error.
//
*End -= 2; if ( LocalConvertStringSidToSid( String, SID, End) == FALSE ) {
Err = GetLastError(); }
if ( Err == ERROR_SUCCESS && *SID != NULL ) {
*FreeSid = TRUE; } }
} else {
//
// If the entry that's been selected hasn't been initialized yet, do it now
//
*SID = MatchedEntry->Sid; }
return(Err); }
DWORD LocalGetStringForSid( IN PSID Sid, OUT PWSTR *String, IN PSID RootDomainSid OPTIONAL ) /*++
Routine Description:
This routine will determine which string represents a sid, either as a sid moniker or as a string representation of a sid (ie: "DA or "S-1-0-0" )
The returned string must be free via a call to LocalFree
Arguments:
Sid - Sid to be converted
String - Where the mapped Sid is to be returned
Return Value:
ERROR_SUCCESS - success
ERROR_NON_MAPPED - An invalid format of the SID was given
ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
--*/ { DWORD Err = ERROR_SUCCESS; PSTRSD_SID_LOOKUP MatchedEntry; PSID pSidSA=NULL; DWORD Len;
if ( Sid == NULL || String == NULL ) {
return(ERROR_INVALID_PARAMETER); }
//
// Try to find a match in the lookup table
//
MatchedEntry = LookupSidInTable( NULL, Sid, RootDomainSid, NULL, NULL, FALSE, (PVOID *)&pSidSA );
//
// If a match was found, return it
//
if ( MatchedEntry || pSidSA ) {
if ( MatchedEntry ) { Len = MatchedEntry->KeyLen; } else { Len = wcslen(SDDL_SCHEMA_ADMINISTRATORS); }
*String = LocalAlloc( LMEM_FIXED, ( Len * sizeof( WCHAR ) ) + sizeof( WCHAR ) ); if ( *String == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
if ( MatchedEntry ) { wcscpy( *String, MatchedEntry->Key ); } else { wcscpy( *String, SDDL_SCHEMA_ADMINISTRATORS); } }
} else {
if ( ConvertSidToStringSidW( Sid, String ) == FALSE ) {
Err = GetLastError(); }
}
return(Err); }
DWORD LocalGetStringForControl( IN SECURITY_DESCRIPTOR_CONTROL ControlCode, IN ULONG LookupFlags, OUT PWSTR *ControlString ) { DWORD i, ControlCount = sizeof( ControlLookup ) / sizeof( STRSD_KEY_LOOKUP ); WCHAR Buffer[256]; DWORD nOffset=0;
if ( !ControlString ) { return(ERROR_INVALID_PARAMETER); }
*ControlString = NULL;
for ( i = 0; i < ControlCount; i++ ) {
//
// If it doesn't match our lookup type, skip it.
//
if ( ( LookupFlags & ControlLookup[ i ].ValidityFlags ) != LookupFlags ) {
continue; }
if ( ControlCode & ControlLookup[ i ].Value ) {
wcsncpy(Buffer+nOffset, ControlLookup[ i ].Key, ControlLookup[ i ].KeyLen );
nOffset += ControlLookup[ i ].KeyLen;
} }
Buffer[nOffset] = L'\0';
if ( nOffset ) { *ControlString = (PWSTR)LocalAlloc(0, (nOffset+1)*sizeof(WCHAR));
if ( *ControlString ) {
wcscpy(*ControlString, Buffer);
} else { return(ERROR_NOT_ENOUGH_MEMORY); } }
return( ERROR_SUCCESS ); }
PSTRSD_KEY_LOOKUP LookupAccessMaskInTable( IN PWSTR String, OPTIONAL IN ULONG AccessMask, OPTIONAL IN ULONG LookupFlags ) /*++
Routine Description:
This routine will determine if the given access mask or string right exists in the lookup table.
A pointer to the matching static lookup entry is returned.
Arguments:
String - The string to be looked up
AccessMask - The accessMask to be looked up.
LookupFlags - Flags to use for lookup (Dacl or Sacl)
Return Value:
Lookup table entry if found
NULL if not found
--*/ { //
// This is how the access mask is looked up. Always have the multi-char
// rights before the single char ones
//
static STRSD_KEY_LOOKUP RightsLookup[] = { { SDDL_READ_PROPERTY, SDDL_LEN_TAG( SDDL_READ_PROPERTY ), ACTRL_DS_READ_PROP, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_WRITE_PROPERTY, SDDL_LEN_TAG( SDDL_WRITE_PROPERTY ), ACTRL_DS_WRITE_PROP, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_CREATE_CHILD, SDDL_LEN_TAG( SDDL_CREATE_CHILD ), ACTRL_DS_CREATE_CHILD, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_DELETE_CHILD, SDDL_LEN_TAG( SDDL_DELETE_CHILD ), ACTRL_DS_DELETE_CHILD, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_LIST_CHILDREN, SDDL_LEN_TAG( SDDL_LIST_CHILDREN ), ACTRL_DS_LIST, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_SELF_WRITE, SDDL_LEN_TAG( SDDL_SELF_WRITE ), ACTRL_DS_SELF, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_LIST_OBJECT, SDDL_LEN_TAG( SDDL_LIST_OBJECT ), ACTRL_DS_LIST_OBJECT, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_DELETE_TREE, SDDL_LEN_TAG( SDDL_DELETE_TREE ), ACTRL_DS_DELETE_TREE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_CONTROL_ACCESS, SDDL_LEN_TAG( SDDL_CONTROL_ACCESS ), ACTRL_DS_CONTROL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL },
{ SDDL_READ_CONTROL, SDDL_LEN_TAG( SDDL_READ_CONTROL ), READ_CONTROL, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_WRITE_DAC, SDDL_LEN_TAG( SDDL_WRITE_DAC ), WRITE_DAC, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_WRITE_OWNER, SDDL_LEN_TAG( SDDL_WRITE_OWNER ), WRITE_OWNER, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_STANDARD_DELETE, SDDL_LEN_TAG( SDDL_STANDARD_DELETE ), DELETE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_GENERIC_ALL, SDDL_LEN_TAG( SDDL_GENERIC_ALL ), GENERIC_ALL, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_GENERIC_READ, SDDL_LEN_TAG( SDDL_GENERIC_READ ), GENERIC_READ, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_GENERIC_WRITE, SDDL_LEN_TAG( SDDL_GENERIC_WRITE ), GENERIC_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_GENERIC_EXECUTE, SDDL_LEN_TAG( SDDL_GENERIC_EXECUTE ), GENERIC_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_FILE_ALL, SDDL_LEN_TAG( SDDL_FILE_ALL ), FILE_ALL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_FILE_READ, SDDL_LEN_TAG( SDDL_FILE_READ ), FILE_GENERIC_READ, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_FILE_WRITE, SDDL_LEN_TAG( SDDL_FILE_WRITE ), FILE_GENERIC_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_FILE_EXECUTE, SDDL_LEN_TAG( SDDL_FILE_EXECUTE ), FILE_GENERIC_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_KEY_ALL, SDDL_LEN_TAG( SDDL_KEY_ALL ), KEY_ALL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_KEY_READ, SDDL_LEN_TAG( SDDL_KEY_READ ), KEY_READ, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_KEY_WRITE, SDDL_LEN_TAG( SDDL_KEY_WRITE ), KEY_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_KEY_EXECUTE, SDDL_LEN_TAG( SDDL_KEY_EXECUTE ), KEY_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL }, }; DWORD i, RightsCount = sizeof(RightsLookup) / sizeof(STRSD_KEY_LOOKUP); PSTRSD_KEY_LOOKUP MatchedEntry = NULL; BOOLEAN LookupString = FALSE;
if ( String ) {
LookupString = TRUE; }
for ( i = 0; i < RightsCount; i++ ) {
//
// If it doesn't match our lookup type, skip it.
//
if ( ( LookupFlags & RightsLookup[ i ].ValidityFlags ) != LookupFlags ) {
continue; }
if ( LookupString ) {
if ( _wcsnicmp( String, RightsLookup[ i ].Key, RightsLookup[ i ].KeyLen ) == 0 ) {
break; }
} else {
if ( AccessMask == RightsLookup[ i ].Value ) {
break; }
}
}
//
// If a match was found, return it
//
if ( i < RightsCount ) {
MatchedEntry = &RightsLookup[ i ]; }
return( MatchedEntry );
}
PSTRSD_KEY_LOOKUP LookupAceTypeInTable( IN PWSTR String, OPTIONAL IN ULONG AceType, OPTIONAL IN ULONG LookupFlags ) /*++
Routine Description:
This routine will determine if the given ace type or string type exists in the lookup table.
A pointer to the matching static lookup entry is returned.
Arguments:
String - The string to be looked up
AceType - The ace type to be looked up.
LookupFlags - Flags to use for lookup (Dacl or Sacl)
Return Value:
Lookup table entry if found
NULL if not found
--*/ { //
// Lookup table
//
static STRSD_KEY_LOOKUP TypeLookup[] = { { SDDL_ACCESS_ALLOWED, SDDL_LEN_TAG( SDDL_ACCESS_ALLOWED ), ACCESS_ALLOWED_ACE_TYPE, SDDL_VALID_DACL }, { SDDL_ACCESS_DENIED, SDDL_LEN_TAG( SDDL_ACCESS_DENIED ), ACCESS_DENIED_ACE_TYPE, SDDL_VALID_DACL }, { SDDL_OBJECT_ACCESS_ALLOWED, SDDL_LEN_TAG( SDDL_OBJECT_ACCESS_ALLOWED ), ACCESS_ALLOWED_OBJECT_ACE_TYPE, SDDL_VALID_DACL }, { SDDL_OBJECT_ACCESS_DENIED, SDDL_LEN_TAG( SDDL_OBJECT_ACCESS_DENIED ), ACCESS_DENIED_OBJECT_ACE_TYPE, SDDL_VALID_DACL }, { SDDL_AUDIT, SDDL_LEN_TAG( SDDL_AUDIT ), SYSTEM_AUDIT_ACE_TYPE, SDDL_VALID_SACL }, { SDDL_ALARM, SDDL_LEN_TAG( SDDL_ALARM ), SYSTEM_ALARM_ACE_TYPE, SDDL_VALID_SACL }, { SDDL_OBJECT_AUDIT, SDDL_LEN_TAG( SDDL_OBJECT_AUDIT ), SYSTEM_AUDIT_OBJECT_ACE_TYPE, SDDL_VALID_SACL }, { SDDL_OBJECT_ALARM, SDDL_LEN_TAG( SDDL_OBJECT_ALARM ), SYSTEM_ALARM_OBJECT_ACE_TYPE, SDDL_VALID_SACL } }; DWORD i, TypeCount = sizeof( TypeLookup ) / sizeof( STRSD_KEY_LOOKUP ); PSTRSD_KEY_LOOKUP MatchedEntry = NULL; BOOLEAN LookupString = FALSE;
if ( String ) {
LookupString = TRUE; }
for ( i = 0; i < TypeCount; i++ ) {
//
// If it doesn't match our lookup type, skip it.
//
if ( ( LookupFlags & TypeLookup[ i ].ValidityFlags ) != LookupFlags ) {
continue; }
if ( LookupString ) {
if ( _wcsnicmp( String, TypeLookup[ i ].Key, TypeLookup[ i ].KeyLen ) == 0 ) {
break; }
} else {
if ( AceType == TypeLookup[ i ].Value ) {
break; }
}
}
//
// If a match was found, return it
//
if ( i < TypeCount ) {
MatchedEntry = &TypeLookup[ i ]; }
return( MatchedEntry ); }
PSTRSD_KEY_LOOKUP LookupAceFlagsInTable( IN PWSTR String, OPTIONAL IN ULONG AceFlags, OPTIONAL IN ULONG LookupFlags ) /*++
Routine Description:
This routine will determine if the given ace flags or string flags exists in the lookup table.
A pointer to the matching static lookup entry is returned.
Arguments:
String - The string to be looked up
AceFlags - The ace flags to be looked up.
LookupFlags - Flags to use for lookup (Dacl or Sacl)
Return Value:
Lookup table entry if found
NULL if not found
--*/ { //
// Lookup tables
//
static STRSD_KEY_LOOKUP FlagLookup[] = { { SDDL_CONTAINER_INHERIT, SDDL_LEN_TAG( SDDL_CONTAINER_INHERIT ), CONTAINER_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_OBJECT_INHERIT, SDDL_LEN_TAG( SDDL_OBJECT_INHERIT ), OBJECT_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_NO_PROPAGATE, SDDL_LEN_TAG( SDDL_NO_PROPAGATE ), NO_PROPAGATE_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_INHERIT_ONLY, SDDL_LEN_TAG( SDDL_INHERIT_ONLY ), INHERIT_ONLY_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_INHERITED, SDDL_LEN_TAG( SDDL_INHERITED ), INHERITED_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL }, { SDDL_AUDIT_SUCCESS, SDDL_LEN_TAG( SDDL_AUDIT_SUCCESS ), SUCCESSFUL_ACCESS_ACE_FLAG, SDDL_VALID_SACL }, { SDDL_AUDIT_FAILURE, SDDL_LEN_TAG( SDDL_AUDIT_FAILURE ), FAILED_ACCESS_ACE_FLAG, SDDL_VALID_SACL } }; DWORD i, FlagCount = sizeof( FlagLookup ) / sizeof( STRSD_KEY_LOOKUP ); PSTRSD_KEY_LOOKUP MatchedEntry = NULL; BOOLEAN LookupString = FALSE;
if ( String ) {
LookupString = TRUE; }
for ( i = 0; i < FlagCount; i++ ) {
//
// If it doesn't match our lookup type, skip it.
//
if ( ( LookupFlags & FlagLookup[ i ].ValidityFlags ) != LookupFlags ) {
continue; }
if ( LookupString ) {
if ( _wcsnicmp( String, FlagLookup[ i ].Key, FlagLookup[ i ].KeyLen ) == 0 ) {
break; }
} else {
if ( AceFlags == FlagLookup[ i ].Value ) {
break; }
}
}
//
// If a match was found, return it
//
if ( i < FlagCount ) {
MatchedEntry = &FlagLookup[ i ]; }
return( MatchedEntry ); }
DWORD LocalGetSDControlForString ( IN PWSTR ControlString, IN ULONG LookupFlags, OUT SECURITY_DESCRIPTOR_CONTROL *pControl, OUT PWSTR *End ) {
DWORD i, ControlCount = sizeof( ControlLookup ) / sizeof( STRSD_KEY_LOOKUP ); PWSTR pCursor=ControlString; BOOL bFound;
if ( !ControlString || !pControl || !End ) {
return(ERROR_INVALID_PARAMETER); }
*pControl = 0;
while ( pCursor && *pCursor == L' ' ) { //
// skip any blanks
//
pCursor++; }
do {
bFound = FALSE;
for ( i = 0; i < ControlCount; i++ ) {
//
// If it doesn't match our lookup type, skip it.
//
if ( ( LookupFlags & ControlLookup[ i ].ValidityFlags ) != LookupFlags ) {
continue; }
if ( _wcsnicmp( pCursor, ControlLookup[ i ].Key, ControlLookup[ i ].KeyLen ) == 0 ) {
*pControl |= ControlLookup[ i ].Value;
pCursor += ControlLookup[ i ].KeyLen;
while ( pCursor && *pCursor == L' ' ) { //
// skip any blanks
//
pCursor++; }
bFound = TRUE;
break; // break the for loop
} }
} while ( bFound );
*End = pCursor;
return( ERROR_SUCCESS );
}
DWORD LocalGetAclForString( IN PWSTR AclString, IN BOOLEAN ConvertAsDacl, OUT PACL *Acl, OUT PWSTR *End, IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL, IN BOOLEAN DefaultToDomain ) /*++
Routine Description:
This routine convert a string into an ACL. The format of the aces is:
Ace := ( Type; Flags; Rights; ObjGuid; IObjGuid; Sid; Type : = A | D | OA | OD {Access, Deny, ObjectAccess, ObjectDeny} Flags := Flags Flag Flag : = CI | IO | NP | SA | FA {Container Inherit,Inherit Only, NoProp, SuccessAudit, FailAdit } Rights := Rights Right Right := DS_READ_PROPERTY | blah blah Guid := String representation of a GUID (via RPC UuidToString) Sid := DA | PS | AO | PO | AU | S-* (Domain Admins, PersonalSelf, Acct Ops, PrinterOps, AuthenticatedUsers, or the string representation of a sid) The seperator is a ';'.
The returned ACL must be free via a call to LocalFree
Arguments:
AclString - The string to be converted
ConvertAsDacl - Treat the input string as a dacl string
ppSid - Where the created SID is to be returned
End - Where in the string we stopped processing
Return Value:
ERROR_SUCCESS indicates success ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput acl failed ERROR_INVALID_PARAMETER The string does not represent an ACL
--*/ { DWORD Err = ERROR_SUCCESS; DWORD AclSize = 0, AclUsed = 0; ULONG Acls = 0, i, j; PWSTR Curr, MaskEnd; WCHAR ConvertGuidString[ STRING_GUID_LEN + 1]; BOOLEAN FreeSid = FALSE; BOOL OpRes; PSTRSD_KEY_LOOKUP MatchedEntry; ULONG LookupFlags; PSID SidPtr = NULL;
if ( NULL == AclString || NULL == Acl || NULL == End ) { return(ERROR_INVALID_PARAMETER); }
if ( ConvertAsDacl ) {
LookupFlags = SDDL_VALID_DACL;
} else {
LookupFlags = SDDL_VALID_SACL; }
//
// First, we'll have to go through and count the number of entries that
// we have. We'll do the by computing the length of this ACL (which is
// delimited by either the end of the list or a ':' that seperates a key
// from a value
//
*End = wcschr( AclString, SDDL_DELIMINATORC );
if ( *End == AclString ) { return(ERROR_INVALID_PARAMETER); }
if ( *End == NULL ) {
*End = AclString + wcslen( AclString );
} else {
( *End )--; }
//
// Now, do the count
//
Curr = AclString;
OpRes = 0; // while ( Curr != *End ) {
while ( Curr < *End ) {
if ( *Curr == SDDL_SEPERATORC ) {
Acls++;
} else if ( *Curr != L' ' ) { OpRes = 1; }
Curr++; }
//
// Now, we've counted the total number of seperators. Make sure we
// have the right number. (There is 5 seperators per ace)
//
if ( Acls % 5 == 0 ) {
if ( Acls == 0 && OpRes ) { //
// gabbage chars in between
//
Err = ERROR_INVALID_PARAMETER;
} else { Acls = Acls / 5; }
} else {
Err = ERROR_INVALID_PARAMETER; }
if ( Err == ERROR_SUCCESS && Acls == 0 ) {
*Acl = LocalAlloc( LMEM_FIXED, sizeof( ACL ) );
if ( *Acl == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
( *Acl )->AclRevision = ACL_REVISION; ( *Acl )->Sbz1 = ( BYTE )0; ( *Acl )->AclSize = ( USHORT )sizeof( ACL ) ; ( *Acl )->AceCount = 0; ( *Acl )->Sbz2 = ( USHORT )0;
}
return( Err ); }
//
// Ok now do the allocation. We'll do a sort of worst case initial
// allocation. This saves us from having to process everything twice
// (once to size, once to build). If we determine later that we have
// an acl that is not big enough, we allocate additional space. The only
// time that this reallocation should happen is if the input string
// contains a lot of explicit SIDs. Otherwise, the chosen buffer size
// should be pretty close to the proper size
//
if ( Err == ERROR_SUCCESS ) {
AclSize = sizeof( ACL ) + ( Acls * ( sizeof( ACCESS_ALLOWED_OBJECT_ACE ) + sizeof( SID ) + ( 6 * sizeof( ULONG ) ) ) ); if ( AclSize > SDDL_MAX_ACL_SIZE ) { AclSize = SDDL_MAX_ACL_SIZE; }
*Acl = ( PACL )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, AclSize );
if ( *Acl == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
AclUsed = sizeof( ACL );
//
// We'll start initializing it...
//
( *Acl )->AclRevision = ACL_REVISION; ( *Acl )->Sbz1 = ( BYTE )0; ( *Acl )->AclSize = ( USHORT )AclSize; ( *Acl )->AceCount = 0; ( *Acl )->Sbz2 = ( USHORT )0;
//
// Ok, now we'll go through and start building them all
//
Curr = AclString;
for( i = 0; i < Acls; i++ ) {
//
// First, get the type..
//
UCHAR Type; UCHAR Flags = 0; USHORT Size; ACCESS_MASK Mask = 0; GUID *ObjId = NULL, ObjGuid; GUID *IObjId = NULL, IObjGuid; PWSTR Next; DWORD AceSize = 0;
//
// skip any space before (
//
while(*Curr == L' ' ) { Curr++; } //
// Skip any parens that may exist in the ace list
//
if ( *Curr == SDDL_ACE_BEGINC ) {
Curr++; } //
// skip any space after (
//
while(*Curr == L' ' ) { Curr++; }
MatchedEntry = LookupAceTypeInTable( Curr, 0, LookupFlags );
if ( MatchedEntry ) {
Type = ( UCHAR )MatchedEntry->Value; Curr += MatchedEntry->KeyLen + 1;
} else {
//
// Found an invalid type
//
Err = ERROR_INVALID_DATATYPE; break; }
//
// If we have any object aces, set the acl revision to REVISION_DS
//
if ( Type >= ACCESS_MIN_MS_OBJECT_ACE_TYPE && Type <= ACCESS_MAX_MS_OBJECT_ACE_TYPE ) {
( *Acl )->AclRevision = ACL_REVISION_DS; }
//
// skip any space before ;
//
while(*Curr == L' ' ) { Curr++; }
//
// Next, get the flags...
//
while ( Curr != *End ) {
if ( *Curr == SDDL_SEPERATORC ) {
Curr++; break; }
//
// Skip any blanks
//
while ( *Curr == L' ' ) {
Curr++; }
MatchedEntry = LookupAceFlagsInTable( Curr, 0, LookupFlags );
if ( MatchedEntry ) {
Flags |= ( UCHAR )MatchedEntry->Value; Curr += MatchedEntry->KeyLen;
} else { //
// Found an invalid flag
//
Err = ERROR_INVALID_FLAGS; break; } }
if ( Err != ERROR_SUCCESS ) {
break; }
//
// skip any space after ;
//
while(*Curr == L' ' ) { Curr++; }
//
// Now, get the access mask
//
while( TRUE ) {
if ( *Curr == SDDL_SEPERATORC ) {
Curr++; break; }
//
// Skip any blanks
//
while ( *Curr == L' ' ) {
Curr++; }
MatchedEntry = LookupAccessMaskInTable( Curr, 0, LookupFlags );
if ( MatchedEntry ) {
Mask |= MatchedEntry->Value; Curr += MatchedEntry->KeyLen;
} else {
//
// If the rights couldn't be looked up, see if it's a converted mask
//
Mask |= wcstoul( Curr, &MaskEnd, 0 );
if ( MaskEnd != Curr ) {
Curr = MaskEnd;
} else { //
// Found an invalid right
//
Err = ERROR_INVALID_ACL; break; } } }
if ( Err != ERROR_SUCCESS ) {
break; }
//
// If that worked, we'll get the ids
//
for ( j = 0; j < 2; j++ ) {
//
// skip any space before ;
//
while(*Curr == L' ' ) { Curr++; }
if ( *Curr != SDDL_SEPERATORC ) {
wcsncpy( ConvertGuidString, Curr, STRING_GUID_LEN ); ConvertGuidString[ STRING_GUID_LEN ] = UNICODE_NULL;
if ( j == 0 ) {
if ( UuidFromStringW( ConvertGuidString, &ObjGuid ) == RPC_S_OK ) {
ObjId = &ObjGuid;
} else {
Err = RPC_S_INVALID_STRING_UUID; break; }
} else {
if ( UuidFromStringW( ConvertGuidString, &IObjGuid ) == RPC_S_OK ) {
IObjId = &IObjGuid;
} else {
Err = RPC_S_INVALID_STRING_UUID; break; } }
// success
Curr += STRING_GUID_LEN; if ( *Curr != SDDL_SEPERATORC && *Curr != L' ' ) {
Err = RPC_S_INVALID_STRING_UUID; break; }
}
Curr++; }
if ( Err != ERROR_SUCCESS ) {
break; }
//
// skip any space before ;
//
while(*Curr == L' ' ) { Curr++; }
//
// Finally, the SID
//
if ( ERROR_SUCCESS == Err ) {
PWSTR End; Err = LocalGetSidForString( Curr, &SidPtr, &End, &FreeSid, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain );
if ( Err == ERROR_SUCCESS ) {
if ( End == NULL ) { Err = ERROR_INVALID_ACL; } else {
while(*End == L' ' ) { End++; } //
// a ace must be terminated by ')'
//
if ( *End != SDDL_ACE_ENDC ) { Err = ERROR_INVALID_ACL;
} else {
Curr = End + 1;
if ( !SidPtr ) { Err = ERROR_INVALID_ACL; } } }
} }
//
// Quit on an error
//
if ( Err != ERROR_SUCCESS ) {
break; }
//
// Now, we'll create the ace, and add it...
//
//
// First, make sure we have the room for it
//
switch ( Type ) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE:
AceSize = sizeof( ACCESS_ALLOWED_ACE ); break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: AceSize = sizeof( KNOWN_OBJECT_ACE );
if ( ObjId ) {
AceSize += sizeof ( GUID ); }
if ( IObjId ) {
AceSize += sizeof ( GUID ); } break;
default: Err = ERROR_INVALID_ACL; break;
}
if ( Err != ERROR_SUCCESS ) {
break; }
AceSize += RtlLengthSid( SidPtr ) - sizeof( ULONG );
if (AceSize + AclUsed > AclSize) { //
// We'll have to reallocate, since our buffer isn't
// big enough...
//
PACL NewAcl; DWORD NewSize = AclSize + ( ( Acls - i ) * AceSize );
NewAcl = ( PACL )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, NewSize ); if ( NewAcl == NULL ) {
LocalFree( *Acl ); *Acl = NULL;
if ( FreeSid == TRUE ) {
LocalFree( SidPtr ); SidPtr = NULL;
FreeSid = FALSE; }
Err = ERROR_NOT_ENOUGH_MEMORY; break;
} else {
memcpy( NewAcl, *Acl, AclSize ); NewAcl->AclSize = ( USHORT )NewSize;
LocalFree( *Acl ); *Acl = NewAcl;
AclSize = NewSize; }
}
AclUsed += AceSize;
SetLastError( ERROR_SUCCESS );
switch (Type) { case SYSTEM_AUDIT_ACE_TYPE: OpRes = AddAuditAccessAceEx( *Acl, ACL_REVISION, Flags & ~(SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG), Mask, SidPtr, Flags & SUCCESSFUL_ACCESS_ACE_FLAG, Flags & FAILED_ACCESS_ACE_FLAG ); break;
case ACCESS_ALLOWED_ACE_TYPE: OpRes = AddAccessAllowedAceEx( *Acl, ACL_REVISION, Flags, Mask, SidPtr );
break;
case ACCESS_DENIED_ACE_TYPE: OpRes = AddAccessDeniedAceEx( *Acl, ACL_REVISION, Flags, Mask, SidPtr );
break;
case SYSTEM_AUDIT_OBJECT_ACE_TYPE: OpRes = AddAuditAccessObjectAce( *Acl, ACL_REVISION_DS, Flags, Mask, ObjId, IObjId, SidPtr, Flags & SUCCESSFUL_ACCESS_ACE_FLAG, Flags & FAILED_ACCESS_ACE_FLAG ); break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE: OpRes = AddAccessAllowedObjectAce( *Acl, ACL_REVISION_DS, Flags, Mask, ObjId, IObjId, SidPtr ); break;
case ACCESS_DENIED_OBJECT_ACE_TYPE: OpRes = AddAccessDeniedObjectAce( *Acl, ACL_REVISION_DS, Flags, Mask, ObjId, IObjId, SidPtr );
break;
default: SetLastError( ERROR_INVALID_DATATYPE ); OpRes = FALSE; break;
}
if ( OpRes == FALSE ) {
Err = GetLastError(); break; }
//
// Clean up whatever memory we have to
//
if ( FreeSid == TRUE ) {
LocalFree( SidPtr ); }
SidPtr = NULL;
if ( *Curr == SDDL_ACE_BEGINC ) {
Curr++; }
}
//
// If something didn't work, clean up
//
if ( Err != ERROR_SUCCESS ) {
LocalFree( *Acl ); *Acl = NULL;
} else {
//
// Set a more realistic acl size
//
( *Acl )->AclSize = ( USHORT )AclUsed; }
//
// free any SIDs buffer used
//
if ( FreeSid && SidPtr ) { LocalFree(SidPtr); SidPtr = NULL; }
FreeSid = FALSE; } }
return(Err); }
DWORD LocalConvertAclToString( IN PACL Acl, IN BOOLEAN AclPresent, IN BOOLEAN ConvertAsDacl, OUT PWSTR *AclString, OUT PDWORD AclStringSize, IN PSID RootDomainSid OPTIONAL ) /*++
Routine Description:
This routine convert an acl into a string. The format of the aces is:
Ace := ( Type; Flags; Rights; ObjGuid; IObjGuid; Sid; Type : = A | D | OA | OD {Access, Deny, ObjectAccess, ObjectDeny} Flags := Flags Flag Flag : = CI | IO | NP | SA | FA {Container Inherit,Inherit Only, NoProp, SuccessAudit, FailAdit } Rights := Rights Right Right := DS_READ_PROPERTY | blah blah Guid := String representation of a GUID (via RPC UuidToString) Sid := DA | PS | AO | PO | AU | S-* (Domain Admins, PersonalSelf, Acct Ops, PrinterOps, AuthenticatedUsers, or the string representation of a sid) The seperator is a ';'.
The returned string must be free via a call to LocalFree
Arguments:
Acl - The acl to be converted
AclPresent - if TRUE, the acl is present, even if NULL
AclString - Where the created acl string is to be returned
ConvertAsDacl - Convert the given acl as the DACL, not the SACL
AclStringLen - The size of the allocated string is returned here
Return Value:
ERROR_SUCCESS - success
ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput acl failed
ERROR_INVALID_PARAMETER The string does not represent an ACL
ERROR_INVALID_ACL - An unexpected access mask was encountered or a NULL acl was encountered
--*/ { DWORD Err = ERROR_SUCCESS; DWORD AclSize = 0, MaskSize; PACE_HEADER AceHeader; ULONG i, j; PWSTR *SidStrings = NULL, Curr, Guid; BOOLEAN *SidFrees = NULL; UINT *pMaskAsString = NULL; PSTRSD_KEY_LOOKUP MatchedEntry; PSTRSD_SID_LOOKUP MatchedSidEntry; PKNOWN_ACE KnownAce; PKNOWN_OBJECT_ACE KnownObjectAce; ACCESS_MASK AccessMask; PSID Sid, pSidSA=NULL; GUID *Obj, *Inherit; ULONG LookupFlags; ULONG AceFlags[ ] = { OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, NO_PROPAGATE_INHERIT_ACE, INHERIT_ONLY_ACE, INHERITED_ACE, SUCCESSFUL_ACCESS_ACE_FLAG, FAILED_ACCESS_ACE_FLAG };
if ( AclString == NULL || AclStringSize == NULL ) { return(ERROR_INVALID_PARAMETER); }
//
// treat the case when (AclPresent == TRUE and Acl == NULL)
// same as the case when AclPresent == FALSE.
// This fix is to be compatible with IsValidSecurityDescriptor()
// when ACL_PRESENT bit is set and Acl == NULL
//
if ( !AclPresent || (AclPresent && (Acl == NULL) ) ) {
*AclString = NULL; *AclStringSize = 0; return( ERROR_SUCCESS );
}
//
// If the ace count is 0, then it's an empty acl, and we don't handle those...
//
if ( Acl->AceCount == 0 ) {
*AclString = NULL; *AclStringSize = 0; return( ERROR_SUCCESS );
}
if ( ConvertAsDacl ) {
LookupFlags = SDDL_VALID_DACL;
} else {
LookupFlags = SDDL_VALID_SACL; }
//
// Allocate buffers to hold sids that are looked up
//
SidStrings = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( PWSTR ) );
if ( SidStrings == NULL ) {
return( ERROR_NOT_ENOUGH_MEMORY ); }
SidFrees = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( BOOLEAN ) );
if ( SidFrees == NULL ) {
LocalFree( SidStrings ); return( ERROR_NOT_ENOUGH_MEMORY ); }
pMaskAsString = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( UINT ) );
if ( pMaskAsString == NULL ) {
LocalFree( SidStrings ); LocalFree( SidFrees ); return( ERROR_NOT_ENOUGH_MEMORY ); }
AceHeader = ( PACE_HEADER )FirstAce( Acl );
//
// Size the acl, so we know how big a buffer to allocate
//
for(i = 0; i < Acl->AceCount && Err == ERROR_SUCCESS; i++, AceHeader = ( PACE_HEADER )NextAce( AceHeader ) ) {
AclSize += sizeof( WCHAR ); //
// First, the type
//
MatchedEntry = LookupAceTypeInTable( NULL, ( ULONG )AceHeader->AceType, LookupFlags );
if ( MatchedEntry ) {
AclSize += SDDL_SIZE_TAG( MatchedEntry->Key ) + SDDL_SIZE_SEP( SDDL_SEPERATORC );
} else {
//
// Found an invalid type
//
Err = ERROR_INVALID_ACL; break; }
//
// Next, process the ace flags
//
for ( j = 0; j < sizeof( AceFlags ) / sizeof( ULONG ); j++ ) {
if ( ( ULONG )AceHeader->AceFlags & ( AceFlags[ j ] ) ) {
MatchedEntry = LookupAceFlagsInTable( 0, AceFlags[ j ], LookupFlags ); if ( MatchedEntry ) {
AclSize += SDDL_SIZE_TAG( MatchedEntry->Key ); } } }
if ( Err != ERROR_SUCCESS ) {
break;
} else {
AclSize += SDDL_SIZE_SEP( SDDL_SEPERATORC ); }
//
// Next, the rights and optionally the guids. This gets done on a per ace type basis
//
switch ( AceHeader->AceType ) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: KnownAce = ( PKNOWN_ACE )AceHeader; AccessMask = KnownAce->Mask; Sid = ( PSID )&KnownAce->SidStart;
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: KnownObjectAce = ( PKNOWN_OBJECT_ACE )AceHeader; AccessMask = KnownObjectAce->Mask; Sid = RtlObjectAceSid( AceHeader );
//
// Deal with potential guids
//
if ( RtlObjectAceObjectType( AceHeader ) ) {
AclSize += STRING_GUID_SIZE; }
if ( RtlObjectAceInheritedObjectType( AceHeader ) ) {
AclSize += STRING_GUID_SIZE; }
break;
default: Err = ERROR_INVALID_ACL; break;
}
//
// Size the rights
//
if ( Err == ERROR_SUCCESS ) {
MaskSize = 0; pMaskAsString[i] = 0;
//
// lookup for the exact value first
//
MatchedEntry = LookupAccessMaskInTable( 0, AccessMask, LookupFlags );
if ( MatchedEntry ) {
pMaskAsString[i] = 1; MaskSize += SDDL_SIZE_TAG( MatchedEntry->Key );
} else { //
// look for each bit
//
for ( j = 0; j < 32; j++ ) {
if ( AccessMask & ( 1 << j ) ) {
MatchedEntry = LookupAccessMaskInTable( 0, AccessMask & ( 1 << j ), LookupFlags );
if ( MatchedEntry ) {
MaskSize += SDDL_SIZE_TAG( MatchedEntry->Key );
} else {
//
// Found an invalid type. We'll convert the whole thing to a string
//
pMaskAsString[i] = 2; MaskSize = 10 * sizeof( WCHAR ); break; } } } }
if ( Err != ERROR_SUCCESS ) {
break;
} else {
AclSize += MaskSize; AclSize += SDDL_SIZE_SEP( SDDL_SEPERATORC ); } }
if ( Err != ERROR_SUCCESS ) {
break; }
//
// Add in space for the guid seperators
//
AclSize += 2 * SDDL_SIZE_SEP( SDDL_SEPERATORC );
//
// Finally, lookup the sids
//
MatchedSidEntry = LookupSidInTable( NULL, Sid, RootDomainSid, NULL, NULL, FALSE, &pSidSA );
//
// If we didn't find a match, try it as a sid string
//
if ( MatchedSidEntry == NULL ) {
if ( pSidSA ) { //
// when sid lookup finds the sid of SA, pSidSA is assigned to Sid
// so it doesn't need to be freed.
//
SidStrings[ i ] = LocalAlloc( LMEM_FIXED, (wcslen(SDDL_SCHEMA_ADMINISTRATORS)+1)*sizeof(TCHAR) );
if ( SidStrings[ i ] == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY; break;
} else { wcscpy( SidStrings[ i ], SDDL_SCHEMA_ADMINISTRATORS );
SidFrees[ i ] = TRUE; }
} else {
if ( ConvertSidToStringSidW( Sid, &SidStrings[ i ] ) == FALSE ) {
Err = GetLastError(); break;
} else {
SidFrees[ i ] = TRUE; } }
} else {
//
// If the entry that's been selected hasn't been initialized yet, do it now
//
SidStrings[ i ] = MatchedSidEntry->Key; } AclSize += SDDL_SIZE_TAG( SidStrings[ i ] );
AclSize += sizeof( WCHAR ); // Closing paren
AclSize += sizeof( WCHAR ); // Trailing NULL
}
//
// If all of that worked, allocate the return buffer, and build the acl string
//
if ( AclSize == 0 ) { Err = ERROR_INVALID_ACL; }
if ( Err == ERROR_SUCCESS ) {
if ( AclSize % 2 != 0 ) { AclSize++; }
*AclString = LocalAlloc( LMEM_FIXED, AclSize );
if ( *AclString == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY; } }
//
// Build the acl
//
if ( Err == ERROR_SUCCESS ) {
Curr = *AclString;
AceHeader = ( PACE_HEADER )FirstAce( Acl );
//
// Size the acl, so we know how big a buffer to allocate
//
for(i = 0; i < Acl->AceCount && Err == ERROR_SUCCESS; i++, AceHeader = ( PACE_HEADER )NextAce( AceHeader ) ) {
//
// "("
//
*Curr = SDDL_ACE_BEGINC; Curr++;
//
// By the time we get down here, we've ensured that we can lookup all the values,
// so there is no need to check for failure
//
//
// First, the type, must find it
// "T;"
//
MatchedEntry = LookupAceTypeInTable( NULL, ( ULONG )AceHeader->AceType, LookupFlags ); if ( MatchedEntry ) { wcscpy( Curr, MatchedEntry->Key ); Curr += MatchedEntry->KeyLen; } *Curr = SDDL_SEPERATORC; Curr++;
//
// Next, process the ace flags
// "CIIO;"
//
for ( j = 0; j < sizeof( AceFlags ) / sizeof( ULONG ); j++ ) {
if ( ( ULONG )AceHeader->AceFlags & ( AceFlags[ j ] ) ) {
MatchedEntry = LookupAceFlagsInTable( 0, AceFlags[ j ], LookupFlags );
if ( MatchedEntry ) {
wcscpy( Curr, MatchedEntry->Key ); Curr+= MatchedEntry->KeyLen;
}
} } *Curr = SDDL_SEPERATORC; Curr++;
//
// Next, the rights and optionally the guids. This gets done on a per ace type basis
//
Obj = NULL; Inherit = NULL;
switch ( AceHeader->AceType ) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: KnownAce = ( PKNOWN_ACE )AceHeader; AccessMask = KnownAce->Mask; Sid = ( PSID )&KnownAce->SidStart;
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: KnownObjectAce = ( PKNOWN_OBJECT_ACE )AceHeader; AccessMask = KnownObjectAce->Mask; Sid = RtlObjectAceSid( AceHeader );
//
// Deal with potential guids
//
Inherit = RtlObjectAceInheritedObjectType( AceHeader ); Obj = RtlObjectAceObjectType( AceHeader ); break; }
//
// Add the rights
//
if ( pMaskAsString[i] == 2 ) {
wcscpy( Curr, L"0x"); Curr += 2; _ultow( AccessMask, Curr, 16 ); Curr += wcslen( Curr );
} else if ( pMaskAsString[i] == 1 ) {
//
// lookup for the entire value first
//
MatchedEntry = LookupAccessMaskInTable( 0, AccessMask, LookupFlags );
if ( MatchedEntry ) {
wcscpy( Curr, MatchedEntry->Key ); Curr += MatchedEntry->KeyLen; }
} else { // 0
for ( j = 0; j < 32; j++ ) {
if ( AccessMask & (1 << j) ) {
MatchedEntry = LookupAccessMaskInTable( 0, AccessMask & ( 1 << j ), LookupFlags );
if ( MatchedEntry ) {
wcscpy( Curr, MatchedEntry->Key ); Curr += MatchedEntry->KeyLen;
} // else shouldn't happen but if it happens
// it is too late to convert it into 0x format
// because the buffer is already allocated with smaller size.
} } }
*Curr = SDDL_SEPERATORC; Curr++;
//
// Optional object guid
//
if ( Obj ) {
Err = UuidToStringW( Obj, &Guid );
if ( Err != ERROR_SUCCESS ) {
break; }
wcscpy( Curr, Guid ); Curr += wcslen( Guid ); RpcStringFreeW( &Guid );
} *Curr = SDDL_SEPERATORC; Curr++;
if ( Inherit ) {
Err = UuidToStringW( Inherit, &Guid );
if ( Err != ERROR_SUCCESS ) {
break; }
wcscpy( Curr, Guid ); Curr += wcslen( Guid ); RpcStringFreeW( &Guid );
} *Curr = SDDL_SEPERATORC; Curr++;
//
// Finally, the sids
//
wcscpy( Curr, SidStrings[ i ] ); Curr += wcslen( SidStrings[ i ] );
*Curr = SDDL_ACE_ENDC; Curr++; *Curr = UNICODE_NULL;
} }
//
// Free any allocated memory
// jinhuang: should always free the allocated buffer
//
// if ( Err != ERROR_SUCCESS && SidStrings ) {
for ( j = 0; j < Acl->AceCount; j++ ) {
if ( SidFrees[ j ] ) {
LocalFree( SidStrings[ j ] ); } } // }
LocalFree( SidStrings ); LocalFree( SidFrees ); LocalFree( pMaskAsString );
if ( Err != ERROR_SUCCESS ) {
LocalFree(*AclString); *AclString = NULL; *AclStringSize = 0;
} else {
*AclStringSize = AclSize;
}
return( Err ); }
DWORD LocalConvertSDToStringSD_Rev1( IN PSID RootDomainSid OPTIONAL, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN SECURITY_INFORMATION SecurityInformation, OUT LPWSTR *StringSecurityDescriptor, OUT PULONG StringSecurityDescriptorLen OPTIONAL ) /*++
Routine Description:
This routine converts a security descriptor into a string version persuant to SDDL definition
Arguments:
SecurityDescriptor - Security Descriptor to be converted.
SecurityInformation - the security information of which component to be converted
StringSecurityDescriptor - Where the converted SD is returned. Buffer is allocated via LocalAlloc and should be free via LocalFree.
StringSecurityDescriptorLen - optional length of the converted SD buffer.
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
--*/ { DWORD Err = ERROR_SUCCESS; NTSTATUS Status=STATUS_SUCCESS; DWORD ReturnBufferSize = 0, AclSize; PSID Owner = NULL, Group = NULL; PACL Dacl = NULL, Sacl = NULL; BOOLEAN Defaulted, SaclPresent=FALSE, DaclPresent=FALSE; PWSTR OwnerString = NULL, GroupString = NULL, SaclString = NULL, DaclString = NULL; SECURITY_DESCRIPTOR_CONTROL ControlCode; ULONG Revision; PWSTR DaclControl=NULL, SaclControl=NULL;
if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL ) { return(ERROR_INVALID_PARAMETER); }
//
// Get the relevant security descriptor parts
// based on the SecurityInforamtion input parameter
//
if ( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
Status = RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &Owner, &Defaulted ); }
if ( NT_SUCCESS( Status ) && SecurityInformation & GROUP_SECURITY_INFORMATION ) {
Status = RtlGetGroupSecurityDescriptor( SecurityDescriptor, &Group, &Defaulted );
}
if ( NT_SUCCESS( Status ) && SecurityInformation & DACL_SECURITY_INFORMATION ) {
Status = RtlGetDaclSecurityDescriptor( SecurityDescriptor, &DaclPresent, &Dacl, &Defaulted ); }
if ( NT_SUCCESS( Status ) && SecurityInformation & SACL_SECURITY_INFORMATION ) {
Status = RtlGetSaclSecurityDescriptor( SecurityDescriptor, &SaclPresent, &Sacl, &Defaulted ); }
if ( NT_SUCCESS( Status ) ) {
Status = RtlGetControlSecurityDescriptor ( SecurityDescriptor, &ControlCode, &Revision); }
if ( !NT_SUCCESS( Status ) ) {
Err = RtlNtStatusToDosError( Status ); return( Err ); }
//
// make sure the SidLookup table is reinitialized
//
InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
//
// Convert the owner and group, if they exist
//
if ( Owner ) {
Err = LocalGetStringForSid( Owner, &OwnerString, RootDomainSid );
}
if ( Err == ERROR_SUCCESS && Group ) {
Err = LocalGetStringForSid( Group, &GroupString, RootDomainSid ); }
//
// JINHUANG 3/10/98
// get DACL control string
//
if ( Err == ERROR_SUCCESS && ControlCode ) {
Err = LocalGetStringForControl(ControlCode, SDDL_VALID_DACL, &DaclControl); }
//
// get SACL control string
//
if ( Err == ERROR_SUCCESS && ControlCode ) {
Err = LocalGetStringForControl(ControlCode, SDDL_VALID_SACL, &SaclControl); }
//
// SACL first because the size of DACL is needed later
//
if ( Err == ERROR_SUCCESS && SaclPresent ) {
Err = LocalConvertAclToString( Sacl, SaclPresent, FALSE, &SaclString, &AclSize, RootDomainSid ); if ( Err == ERROR_SUCCESS ) {
ReturnBufferSize += AclSize; } }
//
// Then, the DACL
//
if ( Err == ERROR_SUCCESS && DaclPresent ) {
Err = LocalConvertAclToString( Dacl, DaclPresent, TRUE, &DaclString, &AclSize, RootDomainSid );
if ( Err == ERROR_SUCCESS ) {
ReturnBufferSize += AclSize; } }
//
// Now, if all of that worked, allocate and build the return string
//
if ( Err == ERROR_SUCCESS ) {
if ( OwnerString ) {
ReturnBufferSize += ( wcslen( OwnerString ) * sizeof( WCHAR ) ) + SDDL_SIZE_TAG( SDDL_OWNER ) + SDDL_SIZE_SEP( SDDL_DELIMINATORC ); }
if ( GroupString ) {
ReturnBufferSize += ( wcslen( GroupString ) * sizeof( WCHAR ) ) + SDDL_SIZE_TAG( SDDL_GROUP ) + SDDL_SIZE_SEP( SDDL_DELIMINATORC ); }
if ( DaclPresent ) {
ReturnBufferSize += SDDL_SIZE_TAG( SDDL_DACL ) + SDDL_SIZE_SEP( SDDL_DELIMINATORC );
if ( DaclControl ) { ReturnBufferSize += (wcslen( DaclControl ) * sizeof(WCHAR)) ; } }
if ( SaclPresent ) {
ReturnBufferSize += SDDL_SIZE_TAG( SDDL_SACL ) + SDDL_SIZE_SEP( SDDL_DELIMINATORC );
if ( SaclControl ) { ReturnBufferSize += (wcslen( SaclControl ) * sizeof(WCHAR)) ; } }
*StringSecurityDescriptor = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, ReturnBufferSize + sizeof( WCHAR ) );
if ( *StringSecurityDescriptor == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
//
// Build the string from the previously determined components. Note that
// if a component is not present, it is skipped.
//
DWORD dwOffset=0;
if ( OwnerString ) {
swprintf( *StringSecurityDescriptor, L"%ws%wc%ws", SDDL_OWNER, SDDL_DELIMINATORC, OwnerString );
dwOffset = wcslen(*StringSecurityDescriptor); }
if ( GroupString ) {
swprintf( *StringSecurityDescriptor + dwOffset, L"%ws%wc%ws", SDDL_GROUP, SDDL_DELIMINATORC, GroupString );
Revision = wcslen( *StringSecurityDescriptor + dwOffset ); // temp use
dwOffset += Revision;
}
if ( DaclPresent ) {
if ( DaclControl ) { swprintf( *StringSecurityDescriptor + dwOffset, L"%ws%wc%ws", SDDL_DACL, SDDL_DELIMINATORC, DaclControl ); } else { swprintf( *StringSecurityDescriptor + dwOffset, L"%ws%wc", SDDL_DACL, SDDL_DELIMINATORC ); }
Revision = wcslen( *StringSecurityDescriptor + dwOffset ); dwOffset += Revision;
if ( DaclString ) {
wcscpy( *StringSecurityDescriptor + dwOffset, DaclString );
Revision = wcslen( *StringSecurityDescriptor + dwOffset ); // temp use
dwOffset += Revision; // (AclSize/sizeof(WCHAR));
}
}
if ( SaclPresent ) {
if ( SaclControl ) {
swprintf( *StringSecurityDescriptor + dwOffset, L"%ws%wc%ws", SDDL_SACL, SDDL_DELIMINATORC, SaclControl ); } else { swprintf( *StringSecurityDescriptor + dwOffset, L"%ws%wc", SDDL_SACL, SDDL_DELIMINATORC ); }
Revision = wcslen( *StringSecurityDescriptor + dwOffset ); dwOffset += Revision;
if ( SaclString ) {
wcscpy( *StringSecurityDescriptor + dwOffset, SaclString); }
}
//
// jinhuang
// output the buffer size
//
if ( StringSecurityDescriptorLen ) { *StringSecurityDescriptorLen = ReturnBufferSize/sizeof(WCHAR); } } }
//
// Free any buffers that were allocated
//
LocalFree( OwnerString ); LocalFree( GroupString ); LocalFree( SaclString ); LocalFree( DaclString );
//
// JINHUANG 3/10/98
// it's ok to free them even if they are NULL
//
LocalFree( SaclControl ); LocalFree( DaclControl );
//
// decrement the SidLookup instance
//
InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
return( Err ); }
DWORD LocalConvertStringSDToSD_Rev1( IN PSID RootDomainSid OPTIONAL, IN PSID DomainSid OPTIONAL, IN BOOLEAN DefaultToDomain, IN LPCWSTR StringSecurityDescriptor, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) /*++
Routine Description:
This routine converts a revision 1 stringized Security descriptor into a valid, functional security descriptor
Arguments:
StringSecurityDescriptor - Stringized security descriptor to be converted.
SecurityDescriptor - Where the converted SD is returned. Buffer is allocated via LocalAlloc and should be free via LocalFree. The returned security descriptor is always self relative
SecurityDescriptorSize - OPTIONAL. If non-NULL, the size of the converted security descriptor is returned here.
SecurityInformation - OPTIONAL. If non-NULL, the security information of the converted security descriptor is returned here.
Return Value:
TRUE - Success FALSE - Failure
Extended error status is available using GetLastError.
ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
ERROR_UNKNOWN_REVISION - An unsupported revision was given
--*/ { DWORD Err = ERROR_SUCCESS; PSID Owner = NULL, Group = NULL; PACL Dacl = NULL, Sacl = NULL; SECURITY_INFORMATION SeInfo = 0; SECURITY_DESCRIPTOR SD; PWSTR Curr, End; NTSTATUS Status; BOOLEAN FreeOwner = FALSE, FreeGroup = FALSE; SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY UaspCreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY; ULONG SDSize = 0; BOOLEAN DaclPresent = FALSE, SaclPresent = FALSE; SECURITY_DESCRIPTOR_CONTROL DaclControl=0, SaclControl=0; PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable = NULL;
if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) { return(ERROR_INVALID_PARAMETER); }
if ( SecurityDescriptorSize ) {
*SecurityDescriptorSize = 0; }
//
// make sure the SidLookup table is reinitialized
//
InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
//
// for the API ConvertStringSDToSDDomain, if DomainSid != NULL, we need a table on
// the heap, for this thread to stash lookups for ST_DOMAIN_RELATIVE type trustees
// this table will be freed when all lookups have been done for this thread
//
if (DomainSid) {
tSidLookupDomOrRootDomRelativeTable = (PSTRSD_SID_LOOKUP) LocalAlloc(LMEM_ZEROINIT, sizeof(SidLookupDomOrRootDomRelative));
//
// table copy/init from the template-table
//
if (tSidLookupDomOrRootDomRelativeTable)
memcpy(tSidLookupDomOrRootDomRelativeTable, SidLookupDomOrRootDomRelative, sizeof(SidLookupDomOrRootDomRelative));
else
Err = ERROR_NOT_ENOUGH_MEMORY;
}
//
// Now, we'll just start parsing and building
//
Curr = ( PWSTR )StringSecurityDescriptor;
while ( Err == ERROR_SUCCESS && Curr ) {
switch( *Curr ) {
//
// Get the Owner sid
//
case L'O':
Err = ERROR_INVALID_PARAMETER;
if ( *(Curr+1) == SDDL_DELIMINATORC ) {
Curr += 2;
if ( Owner == NULL ) {
Err = LocalGetSidForString( Curr, &Owner, &End, &FreeOwner, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain );
if ( Err == ERROR_SUCCESS ) {
Curr = End; SeInfo |= OWNER_SECURITY_INFORMATION; } } } break;
//
// Get the Group sid
//
case L'G':
Err = ERROR_INVALID_PARAMETER;
if ( *(Curr+1) == SDDL_DELIMINATORC ) {
Curr += 2;
if ( Group == NULL ) {
Err = LocalGetSidForString( Curr, &Group, &End, &FreeGroup, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain );
if ( Err == ERROR_SUCCESS ) {
Curr = End; SeInfo |= GROUP_SECURITY_INFORMATION; } } } break;
//
// Next, the DAcl
//
case L'D':
if ( *(Curr+1) == SDDL_DELIMINATORC ) {
Curr += 2;
if ( Dacl == NULL ) {
//
// JINHUANG: 3/10/98
// look for any security descriptor controls
//
if ( *Curr != SDDL_ACE_BEGINC ) {
Err = LocalGetSDControlForString( Curr, SDDL_VALID_DACL, &DaclControl, &End ); if ( Err == ERROR_SUCCESS ) { Curr = End; } }
if ( Err == ERROR_SUCCESS ) {
Err = LocalGetAclForString( Curr, TRUE, &Dacl, &End, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain );
if ( Err == ERROR_SUCCESS ) {
Curr = End; SeInfo |= DACL_SECURITY_INFORMATION; DaclPresent = TRUE; } }
} else {
Err = ERROR_INVALID_PARAMETER; }
} else {
Err = ERROR_INVALID_PARAMETER; } break;
//
// Finally, the SAcl
//
case L'S':
if ( *(Curr+1) == SDDL_DELIMINATORC ) {
Curr += 2;
if ( Sacl == NULL ) {
//
// JINHUANG: 3/10/98
// look for any security descriptor controls
//
if ( *Curr != SDDL_ACE_BEGINC ) {
Err = LocalGetSDControlForString( Curr, SDDL_VALID_SACL, &SaclControl, &End ); if ( Err == ERROR_SUCCESS ) { Curr = End; } }
if ( Err == ERROR_SUCCESS ) {
Err = LocalGetAclForString( Curr, FALSE, &Sacl, &End, RootDomainSid, DomainSid, tSidLookupDomOrRootDomRelativeTable, DefaultToDomain );
if ( Err == ERROR_SUCCESS ) {
Curr = End; SeInfo |= SACL_SECURITY_INFORMATION; SaclPresent = TRUE; } }
} else {
Err = ERROR_INVALID_PARAMETER; }
} else {
Err = ERROR_INVALID_PARAMETER; } break;
//
// It's a space, so ignore it
//
case L' ': Curr++; break;
//
// End of the string, so quit
//
case L'\0': Curr = NULL; break;
//
// Don't know what it is, so consider it an error
//
default: Err = ERROR_INVALID_PARAMETER; break; } }
//
// Ok, if we have the information we need, we'll create the security
// descriptor
//
if ( Err == ERROR_SUCCESS ) {
if ( InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION ) == FALSE ) {
Err = GetLastError(); }
//
// JINHUANG 3/10/98
// set the security descriptor control
//
SD.Control |= (DaclControl | SaclControl);
//
// Now, add the owner and group
//
if ( Err == ERROR_SUCCESS && Owner != NULL ) {
if ( SetSecurityDescriptorOwner(&SD, Owner, FALSE ) == FALSE ) {
Err = GetLastError(); } }
if ( Err == ERROR_SUCCESS && Group != NULL ) {
if ( SetSecurityDescriptorGroup( &SD, Group, FALSE ) == FALSE ) {
Err = GetLastError(); } }
//
// Then the DACL and SACL
//
if ( Err == ERROR_SUCCESS && DaclPresent ) {
if ( SetSecurityDescriptorDacl( &SD, DaclPresent, Dacl, FALSE ) == FALSE ) {
Err = GetLastError(); } }
if ( Err == ERROR_SUCCESS && SaclPresent ) {
if ( SetSecurityDescriptorSacl( &SD, SaclPresent, Sacl, FALSE ) == FALSE ) {
Err = GetLastError(); } }
}
//
// Finally, we'll allocate our buffer and return
//
if ( Err == ERROR_SUCCESS ) {
MakeSelfRelativeSD( &SD, *SecurityDescriptor, &SDSize );
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
*SecurityDescriptor = (PSECURITY_DESCRIPTOR) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, SDSize );
if ( *SecurityDescriptor == NULL ) {
Err = ERROR_NOT_ENOUGH_MEMORY;
} else {
if ( MakeSelfRelativeSD( &SD, *SecurityDescriptor, &SDSize ) == FALSE ) {
Err = GetLastError(); LocalFree( *SecurityDescriptor ); *SecurityDescriptor = NULL;
} }
} else {
//
// This should never happen
//
if ( GetLastError() == ERROR_SUCCESS ) {
Err = ERROR_INSUFFICIENT_BUFFER; } } }
//
// Return the security descriptor size, if requested
//
if ( Err == ERROR_SUCCESS && SecurityDescriptorSize ) {
*SecurityDescriptorSize = SDSize; }
//
// Finally, free any memory we may have allocated...
//
if ( FreeOwner == TRUE ) {
LocalFree( Owner );
}
if ( FreeGroup == TRUE ) {
LocalFree( Group );
}
LocalFree( Dacl ); LocalFree( Sacl );
if (tSidLookupDomOrRootDomRelativeTable)
LocalFree(tSidLookupDomOrRootDomRelativeTable);
//
// make sure the SidLookup table is reinitialized
//
InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
return( Err ); }
STRSD_SID_LOOKUP gDomainSidLookup; STRSD_SID_LOOKUP gDnsDomainSidLookup;
BOOL gbDomainSidCached = FALSE; BOOL gbDnsDomainSidCached = FALSE;
BOOLEAN CacheDomainAndDnsDomainSids( ) { OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status=STATUS_SUCCESS; LSA_HANDLE LsaPolicyHandle; PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL; PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &LsaPolicyHandle );
//
// There's a high probability that both LSA queries succeed or fail together
//
if ( NT_SUCCESS(Status) ) {
Status = LsaQueryInformationPolicy( LsaPolicyHandle, PolicyDnsDomainInformation, ( PVOID * )&DnsDomainInfo );
if ( NT_SUCCESS(Status) && DnsDomainInfo != NULL && DnsDomainInfo->Sid != NULL ) {
RtlCopyMemory( gDnsDomainSidLookup.SidBuff, DnsDomainInfo->Sid, RtlLengthSid( DnsDomainInfo->Sid ) );
gDnsDomainSidLookup.Sid = (PSID) gDnsDomainSidLookup.SidBuff;
gbDnsDomainSidCached = TRUE; }
Status = LsaQueryInformationPolicy( LsaPolicyHandle, PolicyAccountDomainInformation, ( PVOID * )&DomainInfo );
if ( NT_SUCCESS(Status) && DomainInfo != NULL && DomainInfo->DomainSid != NULL ) {
RtlCopyMemory( gDomainSidLookup.SidBuff, DomainInfo->DomainSid, RtlLengthSid( DomainInfo->DomainSid ) );
gDomainSidLookup.Sid = (PSID) gDomainSidLookup.SidBuff; gbDomainSidCached = TRUE; } LsaClose( LsaPolicyHandle );
} LsaFreeMemory( DomainInfo ); LsaFreeMemory( DnsDomainInfo ); return TRUE; }
BOOL gbLookupTableInitialized = FALSE;
BOOLEAN InitializeSidLookupTable( IN BYTE InitFlag ) { SID_IDENTIFIER_AUTHORITY UaspWorldAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY UaspLocalAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY UaspCreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY UaspNtAuthority = SECURITY_NT_AUTHORITY; DWORD i;
EnterCriticalSection(&SddlSidLookupCritical);
switch ( InitFlag ) { case STRSD_REINITIALIZE_ENTER:
SidTableReinitializeInstance++;
if ( SidTableReinitializeInstance > 1 || gbLookupTableInitialized == TRUE) { //
// there is another thread going, or no need to reinitialize the table again
//
LeaveCriticalSection(&SddlSidLookupCritical);
return TRUE; } break;
case STRSD_REINITIALIZE_LEAVE:
if ( SidTableReinitializeInstance > 1 ) { SidTableReinitializeInstance--; } else { SidTableReinitializeInstance = 0; }
LeaveCriticalSection(&SddlSidLookupCritical);
return TRUE; break; }
CacheDomainAndDnsDomainSids();
//
// If the list of sids hasn't been built, do it now
//
// JINHUANG 3/26 BVT break,
// see comments above always try to initialization table
// but skip the ones already initialized for performance
//
for ( i = 0; i < sizeof( SidLookup ) / sizeof( STRSD_SID_LOOKUP ); i++ ) {
if ( STRSD_REINITIALIZE_ENTER == InitFlag ) { SidLookup[ i ].Valid = FALSE; }
if ( SidLookup[ i ].Valid == TRUE && SidLookup[ i ].Sid != NULL ) { //
// this one is already initialized
//
continue; }
SidLookup[ i ].Sid = ( PSID )SidLookup[ i ].SidBuff;
switch ( SidLookup[ i ].SidType ) { case ST_DOMAIN_RELATIVE:
if ( gbDnsDomainSidCached ) {
RtlCopyMemory( SidLookup[ i ].Sid, gDnsDomainSidLookup.Sid, RtlLengthSid( gDnsDomainSidLookup.Sid ) ); ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( SidLookup[ i ].Sid, *( RtlSubAuthorityCountSid( gDnsDomainSidLookup.Sid ) ) ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE;
}
break;
case ST_ROOT_DOMAIN_RELATIVE: //
// will be initialized on demand
//
break;
case ST_WORLD: RtlInitializeSid( SidLookup[ i ].Sid, &UaspWorldAuthority, 1 ); *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; break;
case ST_LOCALSY: RtlInitializeSid( SidLookup[ i ].Sid, &UaspLocalAuthority, 1 ); *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; break;
case ST_LOCAL: if ( gbDomainSidCached ) {
RtlCopyMemory( SidLookup[ i ].Sid, gDomainSidLookup.Sid, RtlLengthSid( gDomainSidLookup.Sid ) );
( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++; *( RtlSubAuthoritySid( SidLookup[ i ].Sid, *( RtlSubAuthorityCountSid( gDomainSidLookup.Sid ) ) ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; } break;
case ST_CREATOR: RtlInitializeSid( SidLookup[ i ].Sid, &UaspCreatorAuthority, 1 ); *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; break;
case ST_NTAUTH: RtlInitializeSid( SidLookup[ i ].Sid, &UaspNtAuthority, 1 ); *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; break;
case ST_BUILTIN: RtlInitializeSid( SidLookup[ i ].Sid, &UaspNtAuthority, 2 ); *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SECURITY_BUILTIN_DOMAIN_RID; *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 1 ) ) = SidLookup[ i ].Rid; SidLookup[ i ].Valid = TRUE; break;
} }
//
// only update gbLookupTableInitialized if LSA Lookups passed
//
if (gbDnsDomainSidCached && gbDomainSidCached) gbLookupTableInitialized = TRUE;
LeaveCriticalSection(&SddlSidLookupCritical);
return TRUE; }
BOOL APIENTRY ConvertStringSDToSDRootDomainA( IN PSID RootDomainSid OPTIONAL, IN LPCSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) { UNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; BOOL Result;
if ( NULL == StringSecurityDescriptor || NULL == SecurityDescriptor ) {
SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); }
RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
Status = SddlpAnsiStringToUnicodeString(&Unicode, &AnsiString);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status );
return FALSE;
}
Result = ConvertStringSDToSDRootDomainW( RootDomainSid, ( LPCWSTR )Unicode.Buffer, StringSDRevision, SecurityDescriptor, SecurityDescriptorSize);
LocalFree( Unicode.Buffer );
if ( Result ) { SetLastError(ERROR_SUCCESS); }
return( Result );
}
BOOL APIENTRY ConvertStringSDToSDRootDomainW( IN PSID RootDomainSid OPTIONAL, IN LPCWSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) {
DWORD Err = ERROR_SUCCESS;
//
// Little elementary parameter checking...
//
if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) {
Err = ERROR_INVALID_PARAMETER;
} else {
switch ( StringSDRevision ) { case SDDL_REVISION_1:
Err = LocalConvertStringSDToSD_Rev1( RootDomainSid, // root domain sid
NULL, // no domain sid is provided for this API
TRUE, // default to domain for EA/SA if root domain sid is not provided
StringSecurityDescriptor, SecurityDescriptor, SecurityDescriptorSize); break;
default:
Err = ERROR_UNKNOWN_REVISION; break; }
}
SetLastError( Err );
return( Err == ERROR_SUCCESS ); }
BOOL APIENTRY ConvertSDToStringSDRootDomainA( IN PSID RootDomainSid OPTIONAL, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN DWORD RequestedStringSDRevision, IN SECURITY_INFORMATION SecurityInformation, OUT LPSTR *StringSecurityDescriptor OPTIONAL, OUT PULONG StringSecurityDescriptorLen OPTIONAL ) { LPWSTR StringSecurityDescriptorW = NULL; ULONG AnsiLen, WideLen = 0; BOOL ReturnValue ;
if ( StringSecurityDescriptor == NULL || 0 == SecurityInformation ) {
SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); }
ReturnValue = ConvertSDToStringSDRootDomainW( RootDomainSid, SecurityDescriptor, RequestedStringSDRevision, SecurityInformation, &StringSecurityDescriptorW, &WideLen );
if ( ReturnValue ) {
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSecurityDescriptorW, WideLen + 1, *StringSecurityDescriptor, 0, NULL, NULL );
if ( AnsiLen != 0 ) {
*StringSecurityDescriptor = LocalAlloc( LMEM_FIXED, AnsiLen );
if ( *StringSecurityDescriptor == NULL ) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); ReturnValue = FALSE;
} else {
AnsiLen = WideCharToMultiByte( CP_ACP, 0, StringSecurityDescriptorW, WideLen + 1, *StringSecurityDescriptor, AnsiLen, NULL, NULL ); ASSERT( AnsiLen != 0 );
if ( AnsiLen == 0 ) {
LocalFree(*StringSecurityDescriptor); *StringSecurityDescriptor = NULL;
ReturnValue = FALSE; }
//
// jinhuang
// output the length (optional)
//
if ( StringSecurityDescriptorLen ) { *StringSecurityDescriptorLen = AnsiLen; }
}
} else {
ReturnValue = FALSE; }
LocalFree(StringSecurityDescriptorW);
}
if ( ReturnValue ) { SetLastError(ERROR_SUCCESS); }
return( ReturnValue );
}
BOOL APIENTRY ConvertSDToStringSDRootDomainW( IN PSID RootDomainSid OPTIONAL, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN DWORD RequestedStringSDRevision, IN SECURITY_INFORMATION SecurityInformation, OUT LPWSTR *StringSecurityDescriptor OPTIONAL, OUT PULONG StringSecurityDescriptorLen OPTIONAL ) {
DWORD Err = ERROR_SUCCESS;
//
// A little parameter checking...
//
if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL || SecurityInformation == 0 ) {
Err = ERROR_INVALID_PARAMETER;
} else {
switch ( RequestedStringSDRevision ) { case SDDL_REVISION_1:
Err = LocalConvertSDToStringSD_Rev1( RootDomainSid, // root domain sid
SecurityDescriptor, SecurityInformation, StringSecurityDescriptor, StringSecurityDescriptorLen ); break;
default: Err = ERROR_UNKNOWN_REVISION; break; }
}
SetLastError( Err );
return( Err == ERROR_SUCCESS);
}
BOOL SddlpGetRootDomainSid(void) { //
// get root domain sid, save it in RootDomSidBuf (global)
// this function is called within the critical section
//
// 1) ldap_open to the DC of interest.
// 2) you do not need to ldap_connect - the following step works anonymously
// 3) read the operational attribute rootDomainNamingContext and provide the
// operational control LDAP_SERVER_EXTENDED_DN_OID as defined in sdk\inc\ntldap.h.
DWORD Win32rc=NO_ERROR; BOOL bRetValue=FALSE;
HINSTANCE hLdapDll=NULL; PFN_LDAP_INIT pfnLdapInit=NULL; PFN_LDAP_SET_OPTION pfnLdapSetOption=NULL; PFN_LDAP_BIND pfnLdapBind=NULL; PFN_LDAP_UNBIND pfnLdapUnbind=NULL; PFN_LDAP_SEARCH pfnLdapSearch=NULL; PFN_LDAP_FIRST_ENTRY pfnLdapFirstEntry=NULL; PFN_LDAP_GET_VALUE pfnLdapGetValue=NULL; PFN_LDAP_MSGFREE pfnLdapMsgFree=NULL; PFN_LDAP_VALUE_FREE pfnLdapValueFree=NULL; PFN_LDAP_MAP_ERROR pfnLdapMapError=NULL;
PLDAP phLdap=NULL;
LDAPControlA serverControls = { LDAP_SERVER_EXTENDED_DN_OID, { 0, (PCHAR) NULL }, TRUE }; LPSTR Attribs[] = { LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT, NULL };
PLDAPControlA rServerControls[] = { &serverControls, NULL }; PLDAPMessage pMessage = NULL; LDAPMessage *pEntry = NULL; PCHAR *ppszValues=NULL;
LPSTR pSidStart, pSidEnd, pParse; BYTE *pDest; BYTE OneByte;
hLdapDll = LoadLibraryA("wldap32.dll");
if ( hLdapDll) { pfnLdapInit = (PFN_LDAP_INIT)GetProcAddress(hLdapDll, "ldap_initA"); pfnLdapSetOption = (PFN_LDAP_SET_OPTION)GetProcAddress(hLdapDll, "ldap_set_option"); pfnLdapBind = (PFN_LDAP_BIND)GetProcAddress(hLdapDll, "ldap_bind_sA"); pfnLdapUnbind = (PFN_LDAP_UNBIND)GetProcAddress(hLdapDll, "ldap_unbind"); pfnLdapSearch = (PFN_LDAP_SEARCH)GetProcAddress(hLdapDll, "ldap_search_ext_sA"); pfnLdapFirstEntry = (PFN_LDAP_FIRST_ENTRY)GetProcAddress(hLdapDll, "ldap_first_entry"); pfnLdapGetValue = (PFN_LDAP_GET_VALUE)GetProcAddress(hLdapDll, "ldap_get_valuesA"); pfnLdapMsgFree = (PFN_LDAP_MSGFREE)GetProcAddress(hLdapDll, "ldap_msgfree"); pfnLdapValueFree = (PFN_LDAP_VALUE_FREE)GetProcAddress(hLdapDll, "ldap_value_freeA"); pfnLdapMapError = (PFN_LDAP_MAP_ERROR)GetProcAddress(hLdapDll, "LdapMapErrorToWin32"); }
if ( pfnLdapInit == NULL || pfnLdapSetOption == NULL || pfnLdapBind == NULL || pfnLdapUnbind == NULL || pfnLdapSearch == NULL || pfnLdapFirstEntry == NULL || pfnLdapGetValue == NULL || pfnLdapMsgFree == NULL || pfnLdapValueFree == NULL || pfnLdapMapError == NULL ) {
Win32rc = ERROR_PROC_NOT_FOUND;
} else {
//
// bind to ldap
//
phLdap = (*pfnLdapInit)(NULL, LDAP_PORT);
if ( phLdap == NULL ) { Win32rc = ERROR_DS_UNAVAILABLE; } else { //
// Turn on the encryption option
//
LONG LdapOption = PtrToLong( LDAP_OPT_ON ); ULONG uLdapStatus = (*pfnLdapSetOption)( phLdap, LDAP_OPT_ENCRYPT, &LdapOption ); Win32rc = (*pfnLdapMapError)( uLdapStatus );
//
// If everything goes on fine, then we can finally bind
//
if (NO_ERROR == Win32rc) { uLdapStatus = (*pfnLdapBind)(phLdap, NULL, NULL, LDAP_AUTH_NEGOTIATE); Win32rc = (*pfnLdapMapError)( uLdapStatus ); } } }
if ( NO_ERROR == Win32rc ) { //
// now get the ldap handle,
//
Win32rc = (*pfnLdapSearch)( phLdap, "", LDAP_SCOPE_BASE, "(objectClass=*)", Attribs, 0, (PLDAPControlA *)&rServerControls, NULL, NULL, 10000, &pMessage);
if( Win32rc == NO_ERROR && pMessage ) {
Win32rc = ERROR_SUCCESS;
pEntry = (*pfnLdapFirstEntry)(phLdap, pMessage);
if(pEntry == NULL) {
Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
} else { //
// Now, we'll have to get the values
//
ppszValues = (*pfnLdapGetValue)(phLdap, pEntry, Attribs[0]);
if( ppszValues == NULL) {
Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
} else if ( ppszValues[0] && ppszValues[0][0] != '\0' ) {
//
// ppszValues[0] is the value to parse.
// The data will be returned as something like:
// <GUID=278676f8d753d211a61ad7e2dfa25f11>;<SID=010400000000000515000000828ba6289b0bc11e67c2ef7f>;DC=colinbrdom1,DC=nttest,DC=microsoft,DC=com
// Parse through this to find the <SID=xxxxxx> part. Note that it may be missing, but the GUID= and trailer should not be.
// The xxxxx represents the hex nibbles of the SID. Translate to the binary form and case to a SID.
pSidStart = strstr(ppszValues[0], "<SID=");
if ( pSidStart ) { //
// find the end of this SID
//
pSidEnd = strchr(pSidStart, '>');
if ( pSidEnd ) {
EnterCriticalSection(&SddlSidLookupCritical);
pParse = pSidStart + 5; pDest = (BYTE *)RootDomSidBuf;
while ( pParse < pSidEnd-1 ) {
if ( *pParse >= '0' && *pParse <= '9' ) { OneByte = (BYTE) ((*pParse - '0') * 16); } else { OneByte = (BYTE) ( (tolower(*pParse) - 'a' + 10) * 16 ); }
if ( *(pParse+1) >= '0' && *(pParse+1) <= '9' ) { OneByte += (BYTE) ( *(pParse+1) - '0' ) ; } else { OneByte += (BYTE) ( tolower(*(pParse+1)) - 'a' + 10 ) ; }
*pDest = OneByte; pDest++; pParse += 2; }
RootDomInited = TRUE;
LeaveCriticalSection(&SddlSidLookupCritical);
bRetValue = TRUE;
} else { Win32rc = ERROR_OBJECT_NOT_FOUND; } } else { Win32rc = ERROR_OBJECT_NOT_FOUND; }
(*pfnLdapValueFree)(ppszValues);
} else { Win32rc = ERROR_OBJECT_NOT_FOUND; } }
(*pfnLdapMsgFree)(pMessage); }
}
//
// even though it's not binded, use unbind to close
//
if ( phLdap != NULL && pfnLdapUnbind ) (*pfnLdapUnbind)(phLdap);
if ( hLdapDll ) { FreeLibrary(hLdapDll); }
SetLastError(Win32rc);
return bRetValue; }
BOOL APIENTRY ConvertStringSDToSDDomainA( IN PSID DomainSid, IN PSID RootDomainSid OPTIONAL, IN LPCSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) /*
Routine Description:
This API is exported from advapi32.dll. This is the ANSI version of ConvertStringSDToSDDomainW and it calls the latter API. See description for ConvertStringSDToSDDomainW.
*/ { UNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; BOOL Result;
if ( NULL == StringSecurityDescriptor || NULL == SecurityDescriptor || NULL == DomainSid || !RtlValidSid(DomainSid) || (RootDomainSid && !RtlValidSid(RootDomainSid)) ) {
SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); }
RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
Status = SddlpAnsiStringToUnicodeString(&Unicode, &AnsiString);
if ( !NT_SUCCESS( Status ) ) {
BaseSetLastNTError( Status );
return FALSE;
}
Result = ConvertStringSDToSDDomainW( DomainSid, RootDomainSid, ( LPCWSTR )Unicode.Buffer, StringSDRevision, SecurityDescriptor, SecurityDescriptorSize);
LocalFree( Unicode.Buffer );
if ( Result ) { SetLastError(ERROR_SUCCESS); }
return( Result );
}
BOOL APIENTRY ConvertStringSDToSDDomainW( IN PSID DomainSid, IN PSID RootDomainSid OPTIONAL, IN LPCWSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ) /*
Routine Description:
This API is exported from advapi32.dll. It is similar to ConvertSDToStringSDRootDomainW except that it takes in a required DomainSid parameter. Domain relative trustees will be resolved w.r.t. DomainSid.
Arguments:
IN PSID DomainSid - pointer to the domain sid w.r.t. which ST_DOMAIN_RELATIVE type trustees are resolved against IN PSID RootDomainSid OPTIONAL - pointer to root domain sid w.r.t. which ST_ROOT_DOMAIN_RELATIVE type trustees are resolved against if this is NULL, the local m/c's root domain is used IN LPCWSTR StringSecurityDescriptor - the input SDDL string IN DWORD StringSDRevision - SDDL revision, only SDDL_REVISION_1 is supported OUT PSECURITY_DESCRIPTOR *SecurityDescriptor - pointer to the constructed security descriptor OUT PULONG SecurityDescriptorSize OPTIONAL - size of the constructed security descriptor
Return Value:
TRUE if succeeded else FALSE. Caller can use GetLastError() to retrieve the error code. */ {
DWORD Err = ERROR_SUCCESS;
//
// Little elementary parameter checking...
//
if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL || DomainSid == NULL || !RtlValidSid(DomainSid) || (RootDomainSid && !RtlValidSid(RootDomainSid)) ) {
Err = ERROR_INVALID_PARAMETER;
} else {
switch ( StringSDRevision ) { case SDDL_REVISION_1:
Err = LocalConvertStringSDToSD_Rev1( RootDomainSid, // no root domain sid maybe provided for this API
DomainSid, // domain sid
FALSE, // domain sid is required
StringSecurityDescriptor, SecurityDescriptor, SecurityDescriptorSize); break;
default:
Err = ERROR_UNKNOWN_REVISION; break; }
}
SetLastError( Err );
return( Err == ERROR_SUCCESS ); }
NTSTATUS SddlpAnsiStringToUnicodeString( OUT PUNICODE_STRING DestinationString, IN PANSI_STRING SourceString )
/*++
Routine Description:
See RtlAnsiStringToUnicodeString - only difference is that Unicode Length is immaterial here. When using this API, never depend on a well formed UNICODE_STRING - only rely on the Buffer field. This functions converts the specified ansi source string into a Unicode string. The translation is done with respect to the current system locale information.
Arguments:
DestinationString - Returns a unicode string that is equivalent to the ansi source string. Should be freed outside using LocalFree()
SourceString - Supplies the ansi source string that is to be converted to unicode.
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no conversion was done. None.
--*/
{ ULONG UnicodeLength; ULONG Index; NTSTATUS st;
UnicodeLength = RtlAnsiStringToUnicodeSize(SourceString);
DestinationString->Buffer = (PWSTR) LocalAlloc(LMEM_ZEROINIT, UnicodeLength); if ( !DestinationString->Buffer ) { return STATUS_NO_MEMORY; }
st = RtlMultiByteToUnicodeN( DestinationString->Buffer, UnicodeLength - sizeof(UNICODE_NULL), &Index, SourceString->Buffer, SourceString->Length );
if (!NT_SUCCESS(st)) { LocalFree(DestinationString->Buffer);
DestinationString->Buffer = NULL; return st; }
DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
return STATUS_SUCCESS;
}
|