From: Andrew Wesie awesie@gmail.com
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/advapi32/security.c | 218 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 164 insertions(+), 54 deletions(-)
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index f081b6b..c03baa7 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -48,6 +48,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(advapi);
static BOOL ParseStringSidToSid(LPCWSTR StringSid, PSID pSid, LPDWORD cBytes); +static DWORD trustee_to_sid(DWORD nDestinationSidLength, PSID pDestinationSid, PTRUSTEEW pTrustee);
typedef struct _ACEFLAG { @@ -1255,16 +1256,122 @@ DWORD WINAPI BuildSecurityDescriptorW( IN ULONG cCountOfAccessEntries, IN PEXPLICIT_ACCESSW pListOfAccessEntries, IN ULONG cCountOfAuditEntries, - IN PEXPLICIT_ACCESSW pListofAuditEntries, + IN PEXPLICIT_ACCESSW pListOfAuditEntries, IN PSECURITY_DESCRIPTOR pOldSD, IN OUT PULONG lpdwBufferLength, OUT PSECURITY_DESCRIPTOR* pNewSD) { - FIXME("(%p,%p,%d,%p,%d,%p,%p,%p,%p) stub!\n",pOwner,pGroup, - cCountOfAccessEntries,pListOfAccessEntries,cCountOfAuditEntries, - pListofAuditEntries,pOldSD,lpdwBufferLength,pNewSD); + SECURITY_DESCRIPTOR desc; + NTSTATUS status; + DWORD ret = ERROR_SUCCESS; + + TRACE("(%p,%p,%d,%p,%d,%p,%p,%p,%p)\n", pOwner, pGroup, + cCountOfAccessEntries, pListOfAccessEntries, cCountOfAuditEntries, + pListOfAuditEntries, pOldSD, lpdwBufferLength, pNewSD);
- return ERROR_CALL_NOT_IMPLEMENTED; + if (pOldSD) + { + SECURITY_DESCRIPTOR_CONTROL control; + DWORD desc_size, dacl_size = 0, sacl_size = 0, owner_size = 0, group_size = 0; + PACL dacl = NULL, sacl = NULL; + PSID owner = NULL, group = NULL; + DWORD revision; + + if ((status = RtlGetControlSecurityDescriptor( pOldSD, &control, &revision )) != STATUS_SUCCESS) + return RtlNtStatusToDosError( status ); + if (!(control & SE_SELF_RELATIVE)) + return ERROR_INVALID_SECURITY_DESCR; + + desc_size = sizeof(desc); + status = RtlSelfRelativeToAbsoluteSD( pOldSD, &desc, &desc_size, dacl, &dacl_size, sacl, &sacl_size, + owner, &owner_size, group, &group_size ); + if (status == STATUS_BUFFER_TOO_SMALL) + { + if (dacl_size) + dacl = LocalAlloc( LMEM_FIXED, dacl_size ); + if (sacl_size) + sacl = LocalAlloc( LMEM_FIXED, sacl_size ); + if (owner_size) + owner = LocalAlloc( LMEM_FIXED, owner_size ); + if (group_size) + group = LocalAlloc( LMEM_FIXED, group_size ); + + desc_size = sizeof(desc); + status = RtlSelfRelativeToAbsoluteSD( pOldSD, &desc, &desc_size, dacl, &dacl_size, sacl, &sacl_size, + owner, &owner_size, group, &group_size ); + } + if (status != STATUS_SUCCESS) + { + LocalFree( dacl ); + LocalFree( sacl ); + LocalFree( owner ); + LocalFree( group ); + return RtlNtStatusToDosError( status ); + } + } + else + { + if ((status = RtlCreateSecurityDescriptor( &desc, SECURITY_DESCRIPTOR_REVISION )) != STATUS_SUCCESS) + return RtlNtStatusToDosError( status ); + } + + if (pOwner) + { + LocalFree( desc.Owner ); + desc.Owner = LocalAlloc( LMEM_FIXED, sizeof(MAX_SID) ); + if ((ret = trustee_to_sid( sizeof(MAX_SID), desc.Owner, pOwner ))) + goto done; + } + + if (pGroup) + { + LocalFree( desc.Group ); + desc.Group = LocalAlloc( LMEM_FIXED, sizeof(MAX_SID) ); + if ((ret = trustee_to_sid( sizeof(MAX_SID), desc.Group, pGroup ))) + goto done; + } + + if (pListOfAccessEntries) + { + PACL new_dacl; + + if ((ret = SetEntriesInAclW( cCountOfAccessEntries, pListOfAccessEntries, desc.Dacl, &new_dacl ))) + goto done; + + LocalFree( desc.Dacl ); + desc.Dacl = new_dacl; + desc.Control |= SE_DACL_PRESENT; + } + + if (pListOfAuditEntries) + { + PACL new_sacl; + + if ((ret = SetEntriesInAclW( cCountOfAuditEntries, pListOfAuditEntries, desc.Sacl, &new_sacl ))) + goto done; + + LocalFree( desc.Sacl ); + desc.Sacl = new_sacl; + desc.Control |= SE_SACL_PRESENT; + } + + *lpdwBufferLength = RtlLengthSecurityDescriptor( &desc ); + *pNewSD = LocalAlloc( LMEM_FIXED, *lpdwBufferLength ); + + if ((status = RtlMakeSelfRelativeSD( &desc, *pNewSD, lpdwBufferLength )) != STATUS_SUCCESS) + { + ret = RtlNtStatusToDosError( status ); + LocalFree( *pNewSD ); + *pNewSD = NULL; + } + +done: + /* free absolute descriptor */ + LocalFree( desc.Owner ); + LocalFree( desc.Group ); + LocalFree( desc.Sacl ); + LocalFree( desc.Dacl ); + return ret; }
/****************************************************************************** @@ -3754,6 +3861,56 @@ static void free_trustee_name(TRUSTEE_FORM form, WCHAR *trustee_nameW) } }
+static DWORD trustee_to_sid( DWORD nDestinationSidLength, PSID pDestinationSid, PTRUSTEEW pTrustee ) +{ + if (pTrustee->MultipleTrusteeOperation == TRUSTEE_IS_IMPERSONATE) + { + WARN("bad multiple trustee operation %d\n", pTrustee->MultipleTrusteeOperation); + return ERROR_INVALID_PARAMETER; + } + + switch (pTrustee->TrusteeForm) + { + case TRUSTEE_IS_SID: + if (!CopySid(nDestinationSidLength, pDestinationSid, pTrustee->ptstrName)) + { + WARN("bad sid %p\n", pTrustee->ptstrName); + return ERROR_INVALID_PARAMETER; + } + break; + case TRUSTEE_IS_NAME: + { + DWORD sid_size = nDestinationSidLength; + DWORD domain_size = MAX_COMPUTERNAME_LENGTH + 1; + SID_NAME_USE use; + if (!strcmpW( pTrustee->ptstrName, CURRENT_USER )) + { + if (!lookup_user_account_name( pDestinationSid, &sid_size, NULL, &domain_size, &use )) + { + return GetLastError(); + } + } + else if (!LookupAccountNameW(NULL, pTrustee->ptstrName, pDestinationSid, &sid_size, NULL, &domain_size, &use)) + { + WARN("bad user name %s\n", debugstr_w(pTrustee->ptstrName)); + return ERROR_INVALID_PARAMETER; + } + break; + } + case TRUSTEE_IS_OBJECTS_AND_SID: + FIXME("TRUSTEE_IS_OBJECTS_AND_SID unimplemented\n"); + break; + case TRUSTEE_IS_OBJECTS_AND_NAME: + FIXME("TRUSTEE_IS_OBJECTS_AND_NAME unimplemented\n"); + break; + default: + WARN("bad trustee form %d\n", pTrustee->TrusteeForm); + return ERROR_INVALID_PARAMETER; + } + + return ERROR_SUCCESS; +} + /****************************************************************************** * SetEntriesInAclA [ADVAPI32.@] */ @@ -3849,56 +4006,9 @@ DWORD WINAPI SetEntriesInAclW( ULONG count, PEXPLICIT_ACCESSW pEntries, pEntries[i].Trustee.TrusteeForm, pEntries[i].Trustee.TrusteeType, pEntries[i].Trustee.ptstrName);
- if (pEntries[i].Trustee.MultipleTrusteeOperation == TRUSTEE_IS_IMPERSONATE) - { - WARN("bad multiple trustee operation %d for trustee %d\n", pEntries[i].Trustee.MultipleTrusteeOperation, i); - ret = ERROR_INVALID_PARAMETER; - goto exit; - } - - switch (pEntries[i].Trustee.TrusteeForm) - { - case TRUSTEE_IS_SID: - if (!CopySid(FIELD_OFFSET(SID, SubAuthority[SID_MAX_SUB_AUTHORITIES]), - ppsid[i], pEntries[i].Trustee.ptstrName)) - { - WARN("bad sid %p for trustee %d\n", pEntries[i].Trustee.ptstrName, i); - ret = ERROR_INVALID_PARAMETER; - goto exit; - } - break; - case TRUSTEE_IS_NAME: - { - DWORD sid_size = FIELD_OFFSET(SID, SubAuthority[SID_MAX_SUB_AUTHORITIES]); - DWORD domain_size = MAX_COMPUTERNAME_LENGTH + 1; - SID_NAME_USE use; - if (!strcmpW( pEntries[i].Trustee.ptstrName, CURRENT_USER )) - { - if (!lookup_user_account_name( ppsid[i], &sid_size, NULL, &domain_size, &use )) - { - ret = GetLastError(); - goto exit; - } - } - else if (!LookupAccountNameW(NULL, pEntries[i].Trustee.ptstrName, ppsid[i], &sid_size, NULL, &domain_size, &use)) - { - WARN("bad user name %s for trustee %d\n", debugstr_w(pEntries[i].Trustee.ptstrName), i); - ret = ERROR_INVALID_PARAMETER; - goto exit; - } - break; - } - case TRUSTEE_IS_OBJECTS_AND_SID: - FIXME("TRUSTEE_IS_OBJECTS_AND_SID unimplemented\n"); - break; - case TRUSTEE_IS_OBJECTS_AND_NAME: - FIXME("TRUSTEE_IS_OBJECTS_AND_NAME unimplemented\n"); - break; - default: - WARN("bad trustee form %d for trustee %d\n", pEntries[i].Trustee.TrusteeForm, i); - ret = ERROR_INVALID_PARAMETER; + ret = trustee_to_sid( FIELD_OFFSET(SID, SubAuthority[SID_MAX_SUB_AUTHORITIES]), ppsid[i], &pEntries[i].Trustee); + if (ret) goto exit; - }
/* Note: we overestimate the ACL size here as a tradeoff between * instructions (simplicity) and memory */