VOID LocalDirCloseEnum( IN OUT HANDLE hEnum ) { LOCAL_ENUM_HANDLE pEnum = (LOCAL_ENUM_HANDLE) hEnum; if (pEnum) { if (pEnum->pEntries) { DirectoryFreeEntries(pEnum->pEntries, pEnum->dwCount); } LwFreeMemory(pEnum); } }
static DWORD LocalDirFindObjectsInternal( IN HANDLE hProvider, IN LSA_FIND_FLAGS FindFlags, IN OPTIONAL LSA_OBJECT_TYPE ObjectType, IN LSA_QUERY_TYPE QueryType, IN DWORD dwCount, IN LSA_QUERY_LIST QueryList, IN OUT PLSA_SECURITY_OBJECT* ppObjects ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameObjectClass[] = LOCAL_DIR_ATTR_OBJECT_CLASS; static WCHAR wszAttrNameUID[] = LOCAL_DIR_ATTR_UID; static WCHAR wszAttrNameGID[] = LOCAL_DIR_ATTR_GID; static WCHAR wszAttrNamePrimaryGroup[] = LOCAL_DIR_ATTR_PRIMARY_GROUP; static WCHAR wszAttrNameSamAccountName[] = LOCAL_DIR_ATTR_SAM_ACCOUNT_NAME; static WCHAR wszAttrNamePassword[] = LOCAL_DIR_ATTR_PASSWORD; static WCHAR wszAttrNameGecos[] = LOCAL_DIR_ATTR_GECOS; static WCHAR wszAttrNameShell[] = LOCAL_DIR_ATTR_SHELL; static WCHAR wszAttrNameHomedir[] = LOCAL_DIR_ATTR_HOME_DIR; static WCHAR wszAttrNameUPN[] = LOCAL_DIR_ATTR_USER_PRINCIPAL_NAME; static WCHAR wszAttrNameObjectSID[] = LOCAL_DIR_ATTR_OBJECT_SID; static WCHAR wszAttrNameDN[] = LOCAL_DIR_ATTR_DISTINGUISHED_NAME; static WCHAR wszAttrNameNetBIOSDomain[] = LOCAL_DIR_ATTR_NETBIOS_NAME; static WCHAR wszAttrNameUserInfoFlags[] = LOCAL_DIR_ATTR_ACCOUNT_FLAGS; static WCHAR wszAttrNameAccountExpiry[] = LOCAL_DIR_ATTR_ACCOUNT_EXPIRY; static WCHAR wszAttrNamePasswdLastSet[] = LOCAL_DIR_ATTR_PASSWORD_LAST_SET; static WCHAR wszAttrNameNTHash[] = LOCAL_DIR_ATTR_NT_HASH; static WCHAR wszAttrNameLMHash[] = LOCAL_DIR_ATTR_LM_HASH; static PWSTR wszAttrs[] = { wszAttrNameObjectClass, wszAttrNameUID, wszAttrNameGID, wszAttrNamePrimaryGroup, wszAttrNameSamAccountName, wszAttrNamePassword, wszAttrNameGecos, wszAttrNameShell, wszAttrNameHomedir, wszAttrNameUPN, wszAttrNameObjectSID, wszAttrNameDN, wszAttrNameNetBIOSDomain, wszAttrNameUserInfoFlags, wszAttrNameAccountExpiry, wszAttrNamePasswdLastSet, wszAttrNameNTHash, wszAttrNameLMHash, NULL }; PDIRECTORY_ENTRY pEntries = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; PCSTR pszFilterTemplateQualified = LOCAL_DB_DIR_ATTR_NETBIOS_NAME " = %Q" \ " AND " LOCAL_DB_DIR_ATTR_SAM_ACCOUNT_NAME " = %Q%s"; PCSTR pszFilterTemplateString = "%s = %Q%s"; PCSTR pszFilterTemplateDword = "%s = %u%s"; PCSTR pszFilterTemplateType = " AND " LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u"; PCSTR pszFilterTemplateUserOrGroup = " AND (" \ LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u OR " \ LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u)"; PCSTR pszFilterBy = NULL; PSTR pszFilterType = NULL; PWSTR pwszFilter = NULL; DWORD dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; DWORD dwIndex = 0; PLSA_LOGIN_NAME_INFO pLoginInfo = NULL; BOOLEAN bLocked = FALSE; BOOLEAN bFoundInvalidObject = FALSE; /* FIXME: support generic queries */ switch (ObjectType) { case LSA_OBJECT_TYPE_UNDEFINED: dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; break; case LSA_OBJECT_TYPE_USER: dwObjectClass = LOCAL_OBJECT_CLASS_USER; break; case LSA_OBJECT_TYPE_GROUP: dwObjectClass = LOCAL_OBJECT_CLASS_GROUP; break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } switch (QueryType) { case LSA_QUERY_TYPE_BY_DN: pszFilterBy = LOCAL_DB_DIR_ATTR_DISTINGUISHED_NAME; break; case LSA_QUERY_TYPE_BY_SID: pszFilterBy = LOCAL_DB_DIR_ATTR_OBJECT_SID; break; case LSA_QUERY_TYPE_BY_NT4: case LSA_QUERY_TYPE_BY_ALIAS: break; case LSA_QUERY_TYPE_BY_UPN: pszFilterBy = LOCAL_DB_DIR_ATTR_USER_PRINCIPAL_NAME; break; case LSA_QUERY_TYPE_BY_UNIX_ID: if (dwObjectClass == LOCAL_OBJECT_CLASS_USER) { pszFilterBy = LOCAL_DB_DIR_ATTR_UID; } else { pszFilterBy = LOCAL_DB_DIR_ATTR_GID; } break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } if (dwObjectClass == LOCAL_OBJECT_CLASS_UNKNOWN) { dwError = LwAllocateStringPrintf( &pszFilterType, pszFilterTemplateUserOrGroup, LOCAL_OBJECT_CLASS_USER, LOCAL_OBJECT_CLASS_GROUP); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LwAllocateStringPrintf( &pszFilterType, pszFilterTemplateType, dwObjectClass); BAIL_ON_LSA_ERROR(dwError); } for (dwIndex = 0; dwIndex < dwCount; dwIndex++) { bFoundInvalidObject = FALSE; switch (QueryType) { case LSA_QUERY_TYPE_BY_ALIAS: case LSA_QUERY_TYPE_BY_NT4: dwError = LsaSrvCrackDomainQualifiedName( QueryList.ppszStrings[dwIndex], &pLoginInfo); BAIL_ON_LSA_ERROR(dwError); if (!pLoginInfo->pszDomain) { LOCAL_RDLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); dwError = LwAllocateString( gLPGlobals.pszNetBIOSName, &pLoginInfo->pszDomain); BAIL_ON_LSA_ERROR(dwError); LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); } dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateQualified, pLoginInfo->pszDomain, pLoginInfo->pszName, pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; case LSA_QUERY_TYPE_BY_DN: case LSA_QUERY_TYPE_BY_SID: case LSA_QUERY_TYPE_BY_UPN: dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateString, pszFilterBy, QueryList.ppszStrings[dwIndex], pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; case LSA_QUERY_TYPE_BY_UNIX_ID: dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateDword, pszFilterBy, QueryList.pdwIds[dwIndex], pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszAttrs, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries > 1) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } else if (dwNumEntries == 1) { pEntry = &pEntries[0]; dwError = LocalMarshalEntryToSecurityObject( pEntry, &ppObjects[dwIndex]); if (dwError) { if (dwError == LW_ERROR_NO_SUCH_OBJECT) { bFoundInvalidObject = TRUE; dwError = 0; } else { BAIL_ON_LSA_ERROR(dwError); } } else { dwError = LocalDirResolveUserObjectPrimaryGroupSid( hProvider, ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); } } if ((dwNumEntries == 0 || bFoundInvalidObject) && QueryType == LSA_QUERY_TYPE_BY_UPN) { /* UPN lookup might fail because the UPN is generated, so try again as an NT4 lookup */ LSA_QUERY_LIST Single; Single.ppszStrings = &QueryList.ppszStrings[dwIndex]; dwError = LocalDirFindObjectsInternal( hProvider, FindFlags, ObjectType, LSA_QUERY_TYPE_BY_NT4, 1, Single, &ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); pEntries = NULL; } if (pLoginInfo) { LsaSrvFreeNameInfo(pLoginInfo); pLoginInfo = NULL; } } cleanup: LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); LW_SAFE_FREE_STRING(pszFilterType); LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } if (pLoginInfo) { LsaSrvFreeNameInfo(pLoginInfo); } return dwError; error: goto cleanup; }
static DWORD LocalDirResolveUserObjectPrimaryGroupSid( IN HANDLE hProvider, IN OUT PLSA_SECURITY_OBJECT pUserObject ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameObjectSID[] = LOCAL_DIR_ATTR_OBJECT_SID; static PWSTR wszAttrs[] = { wszAttrNameObjectSID, NULL }; PCSTR pszTemplate = LOCAL_DB_DIR_ATTR_GID " = %u"; PWSTR pwszFilter = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; if (pUserObject->type != LSA_OBJECT_TYPE_USER) { goto cleanup; } dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszTemplate, pUserObject->userInfo.gid); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszAttrs, FALSE, &pEntry, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries != 1) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } dwError = LocalMarshalAttrToANSIFromUnicodeString( pEntry, wszAttrNameObjectSID, &pUserObject->userInfo.pszPrimaryGroupSid); BAIL_ON_LSA_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntry) { DirectoryFreeEntries(pEntry, dwNumEntries); } return dwError; error: goto cleanup; }
static DWORD LocalDirQueryMemberOfInternal( IN HANDLE hProvider, IN LSA_FIND_FLAGS FindFlags, IN PSTR pszSid, IN OUT PLW_HASH_TABLE pGroupHash ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameDN[] = LOCAL_DIR_ATTR_DISTINGUISHED_NAME; static PWSTR wszResolveAttrs[] = { wszAttrNameDN, NULL }; PDIRECTORY_ENTRY pEntries = NULL; DWORD dwNumEntries = 0; PWSTR pwszFilter = NULL; PWSTR pwszDN = NULL; dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, LOCAL_DB_DIR_ATTR_OBJECT_SID " = %Q", pszSid); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszResolveAttrs, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries > 1) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } else if (dwNumEntries == 1) { dwError = LocalMarshalAttrToUnicodeString( pEntries, wszAttrNameDN, &pwszDN); BAIL_ON_LSA_ERROR(dwError); dwError = LocalDirQueryMemberOfDN( hProvider, FindFlags, pwszDN, pGroupHash); BAIL_ON_LSA_ERROR(dwError); } cleanup: LW_SAFE_FREE_MEMORY(pwszDN); LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } if (dwError == LW_ERROR_NO_SUCH_USER || dwError == LW_ERROR_NO_SUCH_GROUP || dwError == LW_ERROR_NO_SUCH_OBJECT) { dwError = 0; } return dwError; error: goto cleanup; }
static DWORD LocalDirQueryMemberOfDN( IN HANDLE hProvider, IN LSA_FIND_FLAGS FindFlags, IN PWSTR pwszDN, IN OUT PLW_HASH_TABLE pGroupHash ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameObjectSID[] = LOCAL_DIR_ATTR_OBJECT_SID; static PWSTR wszMemberAttrs[] = { wszAttrNameObjectSID, NULL }; PDIRECTORY_ENTRY pEntries = NULL; DWORD dwNumEntries = 0; PSTR pszFilter = NULL; PWSTR pwszFilter = NULL; DWORD dwIndex = 0; PSTR pszGroupSid = NULL; PSTR pszPreviousGroupSid = NULL; dwError = DirectoryGetMemberships( pContext->hDirectory, pwszDN, wszMemberAttrs, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); for (dwIndex = 0; dwIndex < dwNumEntries; dwIndex++) { dwError = LocalMarshalAttrToANSIFromUnicodeString( &pEntries[dwIndex], wszAttrNameObjectSID, &pszGroupSid); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashGetValue( pGroupHash, pszGroupSid, OUT_PPVOID(&pszPreviousGroupSid)); if (dwError == ERROR_NOT_FOUND) { dwError = LwHashSetValue( pGroupHash, pszGroupSid, pszGroupSid); BAIL_ON_LSA_ERROR(dwError); dwError = LocalDirQueryMemberOfInternal( hProvider, FindFlags, pszGroupSid, pGroupHash); pszGroupSid = NULL; BAIL_ON_LSA_ERROR(dwError); } else { BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_MEMORY(pszGroupSid); } cleanup: LW_SAFE_FREE_MEMORY(pwszFilter); LW_SAFE_FREE_MEMORY(pszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } return dwError; error: goto cleanup; }
NTSTATUS SamrSrvQueryAliasInfo( /* [in] */ handle_t hBinding, /* [in] */ ACCOUNT_HANDLE hAlias, /* [in] */ UINT16 level, /* [out] */ AliasInfo **info ) { PCSTR filterFormat = "%s=%Q"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = 0; PACCOUNT_CONTEXT pAcctCtx = NULL; PDOMAIN_CONTEXT pDomCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; PWSTR pwszBase = NULL; WCHAR wszAttrDn[] = DS_ATTR_DISTINGUISHED_NAME; WCHAR wszAttrSamAccountName[] = DS_ATTR_SAM_ACCOUNT_NAME; WCHAR wszAttrDescription[] = DS_ATTR_DESCRIPTION; CHAR szAttrDn[] = DS_ATTR_DISTINGUISHED_NAME; DWORD dwScope = 0; PSTR pszDn = NULL; PWSTR pwszFilter = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwEntriesNum = 0; PDIRECTORY_ENTRY pMemberEntry = NULL; DWORD dwNumMembers = 0; AliasInfo *pAliasInfo = NULL; PWSTR wszAttributesLevel1[] = { wszAttrSamAccountName, wszAttrDescription, NULL }; PWSTR wszAttributesLevel2[] = { wszAttrSamAccountName, NULL }; PWSTR wszAttributesLevel3[] = { wszAttrDescription, NULL }; PWSTR *pwszAttributes[] = { wszAttributesLevel1, wszAttributesLevel2, wszAttributesLevel3 }; PWSTR wszMemberAttributes[] = { wszAttrDn, NULL }; pAcctCtx = (PACCOUNT_CONTEXT)hAlias; if (pAcctCtx == NULL || pAcctCtx->Type != SamrContextAccount) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } if (!(pAcctCtx->dwAccessGranted & ALIAS_ACCESS_LOOKUP_INFO)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } pDomCtx = pAcctCtx->pDomCtx; pConnCtx = pDomCtx->pConnCtx; pwszBase = pDomCtx->pwszDn; dwError = LwWc16sToMbs(pAcctCtx->pwszDn, &pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, filterFormat, szAttrDn, pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch(pConnCtx->hDirectory, pwszBase, dwScope, pwszFilter, pwszAttributes[level - 1], FALSE, &pEntry, &dwEntriesNum); BAIL_ON_LSA_ERROR(dwError); if (dwEntriesNum == 0) { ntStatus = STATUS_INVALID_HANDLE; } else if (dwEntriesNum > 1) { ntStatus = STATUS_INTERNAL_ERROR; } BAIL_ON_NTSTATUS_ERROR(ntStatus); if (level == ALIAS_INFO_ALL) { dwError = DirectoryGetGroupMembers(pConnCtx->hDirectory, pAcctCtx->pwszDn, wszMemberAttributes, &pMemberEntry, &dwNumMembers); BAIL_ON_LSA_ERROR(dwError); } ntStatus = SamrSrvAllocateMemory((void**)&pAliasInfo, sizeof(*pAliasInfo)); BAIL_ON_NTSTATUS_ERROR(ntStatus); switch (level) { case ALIAS_INFO_ALL: ntStatus = SamrFillAliasInfo1(pEntry, dwNumMembers, pAliasInfo); break; case ALIAS_INFO_NAME: ntStatus = SamrFillAliasInfo2(pEntry, pAliasInfo); break; case ALIAS_INFO_DESCRIPTION: ntStatus = SamrFillAliasInfo3(pEntry, pAliasInfo); break; default: ntStatus = STATUS_INVALID_INFO_CLASS; } BAIL_ON_NTSTATUS_ERROR(ntStatus); *info = pAliasInfo; cleanup: LW_SAFE_FREE_MEMORY(pszDn); LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntry) { DirectoryFreeEntries(pEntry, dwEntriesNum); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: if (pAliasInfo) { SamrSrvFreeMemory(pAliasInfo); } *info = NULL; goto cleanup; }
NTSTATUS SamrSrvDeleteAliasMember( handle_t IDL_handle, ACCOUNT_HANDLE hAlias, PSID pSid ) { const wchar_t wszFilterFmt[] = L"%ws='%ws'"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PACCOUNT_CONTEXT pAcctCtx = NULL; PDOMAIN_CONTEXT pDomCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; PWSTR pwszGroupDn = NULL; PWSTR pwszSid = NULL; size_t sSidStrLen = 0; HANDLE hDirectory = NULL; PWSTR pwszBaseDn = NULL; WCHAR wszAttrDn[] = DS_ATTR_DISTINGUISHED_NAME; WCHAR wszAttrObjectClass[] = DS_ATTR_OBJECT_CLASS; WCHAR wszAttrObjectSid[] = DS_ATTR_OBJECT_SID; DWORD dwScope = 0; DWORD dwFilterLen = 0; PWSTR pwszFilter = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwEntriesNum = 0; PWSTR wszAttributes[] = { wszAttrDn, wszAttrObjectClass, NULL }; pAcctCtx = (PACCOUNT_CONTEXT)hAlias; if (pAcctCtx == NULL || pAcctCtx->Type != SamrContextAccount) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } if (!(pAcctCtx->dwAccessGranted & ALIAS_ACCESS_REMOVE_MEMBER)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } pDomCtx = pAcctCtx->pDomCtx; pConnCtx = pDomCtx->pConnCtx; hDirectory = pConnCtx->hDirectory; pwszGroupDn = pAcctCtx->pwszDn; ntStatus = RtlAllocateWC16StringFromSid(&pwszSid, pSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); dwError = LwWc16sLen(pwszSid, &sSidStrLen); BAIL_ON_LSA_ERROR(dwError); dwFilterLen = ((sizeof(wszAttrObjectClass)/sizeof(WCHAR) - 1)) + sSidStrLen + (sizeof(wszFilterFmt)/sizeof(wszFilterFmt[0])); dwError = LwAllocateMemory(sizeof(WCHAR) * dwFilterLen, OUT_PPVOID(&pwszFilter)); BAIL_ON_LSA_ERROR(dwError); if (sw16printfw(pwszFilter, dwFilterLen, wszFilterFmt, wszAttrObjectSid, pwszSid) < 0) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = DirectorySearch(hDirectory, pwszBaseDn, dwScope, pwszFilter, wszAttributes, FALSE, &pEntry, &dwEntriesNum); BAIL_ON_LSA_ERROR(dwError); if (dwEntriesNum > 1) { ntStatus = STATUS_INTERNAL_ERROR; } else if (dwEntriesNum == 0) { ntStatus = STATUS_NO_SUCH_MEMBER; } BAIL_ON_NTSTATUS_ERROR(ntStatus); dwError = DirectoryRemoveFromGroup(hDirectory, pwszGroupDn, pEntry); BAIL_ON_LSA_ERROR(dwError); cleanup: if (pEntry) { DirectoryFreeEntries(pEntry, dwEntriesNum); } LW_SAFE_FREE_MEMORY(pwszFilter); RTL_FREE(&pwszSid); if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }
DWORD LocalDirOpenEnumMembers( IN HANDLE hProvider, OUT PHANDLE phEnum, IN LSA_FIND_FLAGS FindFlags, IN PCSTR pszSid ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameObjectClass[] = LOCAL_DIR_ATTR_OBJECT_CLASS; static WCHAR wszAttrNameObjectSID[] = LOCAL_DIR_ATTR_OBJECT_SID; static WCHAR wszAttrNameDN[] = LOCAL_DIR_ATTR_DISTINGUISHED_NAME; static PWSTR wszResolveAttrs[] = { wszAttrNameObjectClass, wszAttrNameDN, NULL }; static PWSTR wszEnumAttrs[] = { wszAttrNameObjectSID, NULL }; PWSTR pwszFilter = NULL; LOCAL_ENUM_HANDLE hEnum = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; PWSTR pwszDN = NULL; dwError = LwAllocateMemory(sizeof(*hEnum), OUT_PPVOID(&hEnum)); BAIL_ON_LSA_ERROR(dwError); hEnum->hProvider = hProvider; hEnum->type = LOCAL_ENUM_HANDLE_MEMBERS; dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, LOCAL_DB_DIR_ATTR_OBJECT_SID " = %Q", pszSid); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszResolveAttrs, FALSE, &pEntry, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries == 0) { dwError = LW_ERROR_NO_SUCH_OBJECT; BAIL_ON_LSA_ERROR(dwError); } else if (dwNumEntries > 1) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } else { /* FIXME: ensure that sid resolved to a group */ dwError = LocalMarshalAttrToUnicodeString( pEntry, wszAttrNameDN, &pwszDN); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryGetGroupMembers( pContext->hDirectory, pwszDN, wszEnumAttrs, &hEnum->pEntries, &hEnum->dwCount); BAIL_ON_LSA_ERROR(dwError); dwError = LocalGetSequenceNumber( pContext, &hEnum->llSequenceNumber); BAIL_ON_LSA_ERROR(dwError); } *phEnum = hEnum; cleanup: LW_SAFE_FREE_MEMORY(pwszFilter); LW_SAFE_FREE_MEMORY(pwszDN); if (pEntry) { DirectoryFreeEntries(pEntry, dwNumEntries); } return dwError; error: if (hEnum) { LocalDirCloseEnum(hEnum); } goto cleanup; }
NTSTATUS SamrSrvGetMembersInAlias( IN handle_t hBinding, IN ACCOUNT_HANDLE hAlias, OUT SID_ARRAY *pSids ) { NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = 0; PACCOUNT_CONTEXT pAcctCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; HANDLE hDirectory = NULL; PWSTR pwszAliasDn = NULL; WCHAR wszAttrObjectSid[] = DS_ATTR_OBJECT_SID; PDIRECTORY_ENTRY pMemberEntries; DWORD dwMembersNum = 0; DWORD i = 0; PWSTR pwszMemberSid = NULL; PSID pMemberSid = NULL; SID_ARRAY Sids = {0}; PWSTR wszAttributes[] = { wszAttrObjectSid, NULL }; pAcctCtx = (PACCOUNT_CONTEXT)hAlias; if (pAcctCtx == NULL || pAcctCtx->Type != SamrContextAccount) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } if (!(pAcctCtx->dwAccessGranted & ALIAS_ACCESS_GET_MEMBERS)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } pConnCtx = (PCONNECT_CONTEXT)pAcctCtx->pDomCtx->pConnCtx; hDirectory = pConnCtx->hDirectory; pwszAliasDn = pAcctCtx->pwszDn; dwError = DirectoryGetGroupMembers(hDirectory, pwszAliasDn, wszAttributes, &pMemberEntries, &dwMembersNum); BAIL_ON_LSA_ERROR(dwError); Sids.dwNumSids = dwMembersNum; ntStatus = SamrSrvAllocateMemory((PVOID*)&Sids.pSids, sizeof(*Sids.pSids) * Sids.dwNumSids); BAIL_ON_NTSTATUS_ERROR(ntStatus); for (i = 0; i < dwMembersNum; i++) { PDIRECTORY_ENTRY pEntry = &(pMemberEntries[i]); dwError = DirectoryGetEntryAttrValueByName( pEntry, wszAttrObjectSid, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszMemberSid); BAIL_ON_LSA_ERROR(dwError); ntStatus = SamrSrvAllocateSidFromWC16String( &pMemberSid, pwszMemberSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); Sids.pSids[i].pSid = pMemberSid; } pSids->dwNumSids = Sids.dwNumSids; pSids->pSids = Sids.pSids; cleanup: if (pMemberEntries) { DirectoryFreeEntries(pMemberEntries, dwMembersNum); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: for (i = 0; i < dwMembersNum; i++) { SamrSrvFreeMemory(Sids.pSids[i].pSid); } SamrSrvFreeMemory(Sids.pSids); memset(pSids, 0, sizeof(*pSids)); goto cleanup; }
NTSTATUS SamrSrvEnumDomainAccounts( IN handle_t hBinding, IN DOMAIN_HANDLE hDomain, IN OUT PDWORD pdwResume, IN DWORD dwObjectClass, IN DWORD dwFlagsFilter, IN DWORD dwMaxSize, OUT RID_NAME_ARRAY **ppNames, OUT UINT32 *pdwNumEntries ) { wchar_t wszFilterFmt[] = L"%ws=%u AND %ws='%ws'"; NTSTATUS ntStatus = STATUS_SUCCESS; NTSTATUS ntEnumStatus = STATUS_SUCCESS; DWORD dwError = 0; PDOMAIN_CONTEXT pDomCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; PWSTR pwszBase = NULL; WCHAR wszAttrObjectClass[] = DS_ATTR_OBJECT_CLASS; WCHAR wszAttrDomainName[] = DS_ATTR_DOMAIN; WCHAR wszAttrAccountFlags[] = DS_ATTR_ACCOUNT_FLAGS; WCHAR wszAttrSamAccountName[] = DS_ATTR_SAM_ACCOUNT_NAME; WCHAR wszAttrObjectSid[] = DS_ATTR_OBJECT_SID; DWORD dwScope = 0; PWSTR pwszFilter = NULL; size_t sDomainNameLen = 0; PWSTR pwszDomainName = NULL; DWORD dwFilterLen = 0; PDIRECTORY_ENTRY pEntries = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; DWORD dwTotalSize = 0; DWORD dwSize = 0; DWORD i = 0; DWORD dwCount = 0; DWORD dwNumEntriesReturned = 0; DWORD dwResume = 0; DWORD dwAccountFlags = 0; size_t sNameLen = 0; PWSTR pwszName = NULL; PWSTR pwszSid = NULL; PSID pSid = NULL; DWORD dwRid = 0; RID_NAME_ARRAY *pNames = NULL; RID_NAME *pName = NULL; DWORD dwNewResumeIdx = 0; PWSTR wszAttributes[] = { wszAttrSamAccountName, wszAttrObjectSid, wszAttrAccountFlags, NULL }; BAIL_ON_INVALID_PTR(hDomain); BAIL_ON_INVALID_PTR(pdwResume); BAIL_ON_INVALID_PTR(ppNames); BAIL_ON_INVALID_PTR(pdwNumEntries); pDomCtx = (PDOMAIN_CONTEXT)hDomain; dwResume = *pdwResume; if (pDomCtx == NULL || pDomCtx->Type != SamrContextDomain) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } if (!(pDomCtx->dwAccessGranted & DOMAIN_ACCESS_ENUM_ACCOUNTS)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } pConnCtx = pDomCtx->pConnCtx; pwszBase = pDomCtx->pwszDn; pwszDomainName = pDomCtx->pwszDomainName; dwError = LwWc16sLen(pwszDomainName, &sDomainNameLen); BAIL_ON_LSA_ERROR(dwError); dwFilterLen = ((sizeof(wszAttrObjectClass)/sizeof(WCHAR)) - 1) + 10 + ((sizeof(wszAttrDomainName)/sizeof(WCHAR)) - 1) + (sDomainNameLen + 1) + (sizeof(wszFilterFmt)/sizeof(wszFilterFmt[0])); dwError = LwAllocateMemory(dwFilterLen * sizeof(pwszFilter[0]), OUT_PPVOID(&pwszFilter)); BAIL_ON_LSA_ERROR(dwError); if (sw16printfw(pwszFilter, dwFilterLen, wszFilterFmt, wszAttrObjectClass, dwObjectClass, wszAttrDomainName, pwszDomainName) < 0) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = DirectorySearch(pConnCtx->hDirectory, pwszBase, dwScope, pwszFilter, wszAttributes, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); ntStatus = SamrSrvAllocateMemory(OUT_PPVOID(&pNames), sizeof(*pNames)); BAIL_ON_NTSTATUS_ERROR(ntStatus); if (dwResume >= dwNumEntries) { ntEnumStatus = STATUS_NO_MORE_ENTRIES; BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwTotalSize += sizeof(pNames->dwCount); for (i = 0; i + dwResume < dwNumEntries; i++) { pEntry = &(pEntries[i + dwResume]); dwError = DirectoryGetEntryAttrValueByName( pEntry, wszAttrSamAccountName, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszName); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryGetEntryAttrValueByName( pEntry, wszAttrAccountFlags, DIRECTORY_ATTR_TYPE_INTEGER, &dwAccountFlags); BAIL_ON_LSA_ERROR(dwError); dwSize = 0; if (dwFlagsFilter && !(dwAccountFlags & dwFlagsFilter)) { continue; } dwError = LwWc16sLen(pwszName, &sNameLen); BAIL_ON_LSA_ERROR(dwError); dwSize += sizeof(UINT32); dwSize += sNameLen * sizeof(pwszName[0]); dwSize += 2 * sizeof(UINT16); dwTotalSize += dwSize; dwCount++; if (dwTotalSize > dwMaxSize) { dwTotalSize -= dwSize; dwCount--; ntEnumStatus = STATUS_MORE_ENTRIES; break; } } /* * At least one entry is returned regardless of declared * max response size */ dwNumEntriesReturned = (dwSize > 0 && dwCount == 0) ? 1 : dwCount; pNames->dwCount = dwNumEntriesReturned; ntStatus = SamrSrvAllocateMemory( OUT_PPVOID(&pNames->pEntries), sizeof(pNames->pEntries[0]) * pNames->dwCount); BAIL_ON_NTSTATUS_ERROR(ntStatus); for (i = 0, dwCount = 0; dwCount < dwNumEntriesReturned && i + dwResume < dwNumEntries; i++) { pEntry = &(pEntries[i + dwResume]); dwError = DirectoryGetEntryAttrValueByName(pEntry, wszAttrObjectSid, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszSid); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryGetEntryAttrValueByName(pEntry, wszAttrSamAccountName, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszName); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryGetEntryAttrValueByName(pEntry, wszAttrAccountFlags, DIRECTORY_ATTR_TYPE_INTEGER, &dwAccountFlags); BAIL_ON_LSA_ERROR(dwError); dwNewResumeIdx = i + dwResume + 1; if (dwFlagsFilter && !(dwAccountFlags & dwFlagsFilter)) { continue; } pName = &(pNames->pEntries[dwCount++]); ntStatus = RtlAllocateSidFromWC16String(&pSid, pwszSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); dwRid = pSid->SubAuthority[pSid->SubAuthorityCount - 1]; pName->dwRid = (UINT32)dwRid; ntStatus = SamrSrvInitUnicodeString(&pName->Name, pwszName); BAIL_ON_NTSTATUS_ERROR(ntStatus); RTL_FREE(&pSid); } *pdwResume = dwNewResumeIdx; *pdwNumEntries = dwNumEntriesReturned; *ppNames = pNames; cleanup: LW_SAFE_FREE_MEMORY(pwszFilter); RTL_FREE(&pSid); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } if (ntStatus == STATUS_SUCCESS && ntEnumStatus != STATUS_SUCCESS) { ntStatus = ntEnumStatus; } return ntStatus; error: if (pNames) { for (i = 0; i < pNames->dwCount; i++) { SamrSrvFreeUnicodeString(&(pNames->pEntries[i].Name)); } SamrSrvFreeMemory(pNames->pEntries); SamrSrvFreeMemory(pNames); } *pdwResume = 0; *pdwNumEntries = 0; *ppNames = NULL; goto cleanup; }
static DWORD SamDbSearchMarshallResultsAttributesValues( PSAM_DIRECTORY_CONTEXT pDirectoryContext, PCSTR pszQuery, PSAM_DB_COLUMN_VALUE pColumnValueList, ULONG ulAttributesOnly, PDIRECTORY_ENTRY* ppDirectoryEntries, PDWORD pdwNumEntries ) { DWORD dwError = 0; PDIRECTORY_ENTRY pDirectoryEntries = NULL; DWORD dwNumEntries = 0; DWORD dwTotalEntries = 0; DWORD dwEntriesAvailable = 0; sqlite3_stmt* pSqlStatement = NULL; DWORD dwNumCols = 0; PSAM_DB_COLUMN_VALUE pIter = NULL; PDIRECTORY_ATTRIBUTE pAttrs = NULL; DWORD dwNumAttrs = 0; for (pIter = pColumnValueList; pIter; pIter = pIter->pNext) { dwNumCols++; } dwError = sqlite3_prepare_v2( pDirectoryContext->pDbContext->pDbHandle, pszQuery, -1, &pSqlStatement, NULL); BAIL_ON_SAMDB_SQLITE_ERROR_DB(dwError, pDirectoryContext->pDbContext->pDbHandle); while ((dwError = sqlite3_step(pSqlStatement)) == SQLITE_ROW) { DWORD iCol = 0; dwNumAttrs = sqlite3_column_count(pSqlStatement); if (dwNumAttrs != dwNumCols) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_SAMDB_ERROR(dwError); } if (!dwEntriesAvailable) { DWORD dwNewEntryCount = dwTotalEntries + 5; dwError = DirectoryReallocMemory( pDirectoryEntries, (PVOID*)&pDirectoryEntries, dwNewEntryCount * sizeof(DIRECTORY_ENTRY)); BAIL_ON_SAMDB_ERROR(dwError); dwEntriesAvailable = dwNewEntryCount - dwTotalEntries; memset((PBYTE)pDirectoryEntries+(dwTotalEntries * sizeof(DIRECTORY_ENTRY)), 0, dwEntriesAvailable * sizeof(DIRECTORY_ENTRY)); dwTotalEntries = dwNewEntryCount; } dwError = DirectoryAllocateMemory( sizeof(DIRECTORY_ATTRIBUTE) * dwNumAttrs, (PVOID*)&pAttrs); BAIL_ON_SAMDB_ERROR(dwError); for (pIter = pColumnValueList; pIter; pIter = pIter->pNext, iCol++) { PDIRECTORY_ATTRIBUTE pAttr = &pAttrs[iCol]; DWORD dwAttrLen = 0; dwError = DirectoryAllocateStringW( pIter->pAttrMap->wszDirectoryAttribute, &pAttr->pwszName); BAIL_ON_SAMDB_ERROR(dwError); switch (pIter->pAttrMap->attributeType) { case SAMDB_ATTR_TYPE_TEXT: dwAttrLen = sqlite3_column_bytes(pSqlStatement, iCol); if (dwAttrLen) { PATTRIBUTE_VALUE pAttrVal = NULL; const unsigned char* pszStringVal = NULL; pszStringVal = sqlite3_column_text( pSqlStatement, iCol); dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; pAttrVal = &pAttr->pValues[0]; pAttrVal->Type = DIRECTORY_ATTR_TYPE_UNICODE_STRING; dwError = LwMbsToWc16s( (PCSTR)pszStringVal, &pAttrVal->data.pwszStringValue); BAIL_ON_SAMDB_ERROR(dwError); } else { pAttr->ulNumValues = 0; } break; case SAMDB_ATTR_TYPE_INT32: case SAMDB_ATTR_TYPE_DATETIME: dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_INTEGER; pAttr->pValues[0].data.ulValue = sqlite3_column_int( pSqlStatement, iCol); break; case SAMDB_ATTR_TYPE_INT64: dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_LARGE_INTEGER; pAttr->pValues[0].data.llValue = sqlite3_column_int64( pSqlStatement, iCol); break; case SAMDB_ATTR_TYPE_BOOLEAN: dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_BOOLEAN; if (sqlite3_column_int(pSqlStatement, iCol)) { pAttr->pValues[0].data.bBooleanValue = TRUE; } else { pAttr->pValues[0].data.bBooleanValue = FALSE; } break; case SAMDB_ATTR_TYPE_BLOB: case SAMDB_ATTR_TYPE_SECURITY_DESCRIPTOR: dwAttrLen = sqlite3_column_bytes(pSqlStatement, iCol); if (dwAttrLen) { PATTRIBUTE_VALUE pAttrVal = NULL; PCVOID pBlob = sqlite3_column_blob( pSqlStatement, iCol); dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; pAttrVal = &pAttr->pValues[0]; if (pIter->pAttrMap->attributeType == SAMDB_ATTR_TYPE_BLOB) { pAttrVal->Type = DIRECTORY_ATTR_TYPE_OCTET_STREAM; } else { pAttrVal->Type = DIRECTORY_ATTR_TYPE_NT_SECURITY_DESCRIPTOR; } dwError = DirectoryAllocateMemory( sizeof(OCTET_STRING), (PVOID*)&pAttrVal->data.pOctetString); BAIL_ON_SAMDB_ERROR(dwError); dwError = DirectoryAllocateMemory( dwAttrLen, (PVOID*)&pAttrVal->data.pOctetString->pBytes); BAIL_ON_SAMDB_ERROR(dwError); memcpy(pAttrVal->data.pOctetString->pBytes, pBlob, dwAttrLen); pAttrVal->data.pOctetString->ulNumBytes = dwAttrLen; } else { pAttr->ulNumValues = 0; } break; default: dwError = LW_ERROR_INTERNAL; BAIL_ON_SAMDB_ERROR(dwError); } } pDirectoryEntries[dwNumEntries].ulNumAttributes = dwNumAttrs; pDirectoryEntries[dwNumEntries].pAttributes = pAttrs; pAttrs = NULL; dwNumAttrs = 0; dwNumEntries++; dwEntriesAvailable--; } if (dwError == SQLITE_DONE) { dwError = LW_ERROR_SUCCESS; } BAIL_ON_SAMDB_SQLITE_ERROR_STMT(dwError, pSqlStatement); *ppDirectoryEntries = pDirectoryEntries; *pdwNumEntries = dwNumEntries; cleanup: if (pSqlStatement) { sqlite3_finalize(pSqlStatement); } return dwError; error: *ppDirectoryEntries = NULL; *pdwNumEntries = 0; if (pAttrs) { DirectoryFreeAttributes(pAttrs, dwNumAttrs); } if (pDirectoryEntries) { DirectoryFreeEntries(pDirectoryEntries, dwTotalEntries); } goto cleanup; }
static DWORD SamDbSearchMarshallResultsAttributes( PSAM_DIRECTORY_CONTEXT pDirectoryContext, PCSTR pszQuery, PSAM_DB_COLUMN_VALUE pColumnValueList, ULONG ulAttributesOnly, PDIRECTORY_ENTRY* ppDirectoryEntries, PDWORD pdwNumEntries ) { DWORD dwError = 0; PDIRECTORY_ENTRY pDirectoryEntries = NULL; PDIRECTORY_ENTRY pDirEntry = NULL; DWORD dwNumEntries = 0; DWORD iCol = 0; PSAM_DB_COLUMN_VALUE pIter = NULL; dwError = DirectoryAllocateMemory( sizeof(DIRECTORY_ENTRY), (PVOID*)&pDirectoryEntries); BAIL_ON_SAMDB_ERROR(dwError); dwNumEntries = 1; pDirEntry = &pDirectoryEntries[0]; for (pIter = pColumnValueList; pIter; pIter = pIter->pNext) { pDirEntry->ulNumAttributes++; } dwError = DirectoryAllocateMemory( sizeof(DIRECTORY_ATTRIBUTE) * pDirEntry->ulNumAttributes, (PVOID*)&pDirEntry->pAttributes); BAIL_ON_SAMDB_ERROR(dwError); for (pIter = pColumnValueList; pIter; pIter = pIter->pNext, iCol++) { PDIRECTORY_ATTRIBUTE pAttr = &pDirEntry->pAttributes[iCol]; dwError = DirectoryAllocateStringW( pIter->pAttrMap->wszDirectoryAttribute, &pAttr->pwszName); BAIL_ON_SAMDB_ERROR(dwError); dwError = DirectoryAllocateMemory( sizeof(ATTRIBUTE_VALUE), (PVOID*)&pAttr->pValues); BAIL_ON_SAMDB_ERROR(dwError); pAttr->ulNumValues = 1; switch (pIter->pAttrMap->attributeType) { case SAMDB_ATTR_TYPE_TEXT: pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_UNICODE_STRING; break; case SAMDB_ATTR_TYPE_INT32: case SAMDB_ATTR_TYPE_BOOLEAN: case SAMDB_ATTR_TYPE_DATETIME: pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_INTEGER; break; case SAMDB_ATTR_TYPE_INT64: pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_LARGE_INTEGER; break; case SAMDB_ATTR_TYPE_BLOB: pAttr->pValues[0].Type = DIRECTORY_ATTR_TYPE_OCTET_STREAM; break; default: dwError = LW_ERROR_DATA_ERROR; BAIL_ON_SAMDB_ERROR(dwError); break; } } *ppDirectoryEntries = pDirectoryEntries; *pdwNumEntries = dwNumEntries; cleanup: return dwError; error: *ppDirectoryEntries = NULL; *pdwNumEntries = 0; if (pDirectoryEntries) { DirectoryFreeEntries(pDirectoryEntries, dwNumEntries); } goto cleanup; }
DWORD SamDbSearchObject_inlock( HANDLE hDirectory, PWSTR pwszBase, ULONG ulScope, PWSTR pwszFilter, PWSTR wszAttributes[], ULONG ulAttributesOnly, PDIRECTORY_ENTRY* ppDirectoryEntries, PDWORD pdwNumEntries ) { DWORD dwError = 0; PSAM_DIRECTORY_CONTEXT pDirectoryContext = NULL; PSTR pszQuery = NULL; BOOLEAN bMembersAttrExists = FALSE; PSAM_DB_COLUMN_VALUE pColumnValueList = NULL; PDIRECTORY_ENTRY pDirectoryEntries = NULL; DWORD dwNumEntries = 0; pDirectoryContext = (PSAM_DIRECTORY_CONTEXT)hDirectory; dwError = SamDbBuildSqlQuery( pDirectoryContext, pwszFilter, wszAttributes, ulAttributesOnly, &pszQuery, &bMembersAttrExists, &pColumnValueList); BAIL_ON_SAMDB_ERROR(dwError); dwError = SamDbSearchExecute( pDirectoryContext, pszQuery, pColumnValueList, ulAttributesOnly, &pDirectoryEntries, &dwNumEntries); BAIL_ON_SAMDB_ERROR(dwError); *ppDirectoryEntries = pDirectoryEntries; *pdwNumEntries = dwNumEntries; cleanup: if (pColumnValueList) { SamDbFreeColumnValueList(pColumnValueList); } DIRECTORY_FREE_STRING(pszQuery); return(dwError); error: if (pDirectoryEntries) { DirectoryFreeEntries(pDirectoryEntries, dwNumEntries); } goto cleanup; }
NTSTATUS SamrSrvQueryUserInfo( /* [in] */ handle_t hBinding, /* [in] */ ACCOUNT_HANDLE hUser, /* [in] */ UINT16 level, /* [out] */ UserInfo **info ) { PCSTR filterFormat = "%s=%Q"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = 0; PACCOUNT_CONTEXT pAcctCtx = NULL; PDOMAIN_CONTEXT pDomCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; PWSTR pwszBase = NULL; WCHAR wszAttrObjectSid[] = DS_ATTR_OBJECT_SID; WCHAR wszAttrSamAccountName[] = DS_ATTR_SAM_ACCOUNT_NAME; WCHAR wszAttrFullName[] = DS_ATTR_FULL_NAME; WCHAR wszAttrPrimaryGroup[] = DS_ATTR_PRIMARY_GROUP; WCHAR wszAttrDescription[] = DS_ATTR_DESCRIPTION; WCHAR wszAttrComment[] = DS_ATTR_COMMENT; WCHAR wszAttrCountryCode[] = DS_ATTR_COUNTRY_CODE; WCHAR wszAttrCodePage[] = DS_ATTR_CODE_PAGE; WCHAR wszAttrHomeDirectory[] = DS_ATTR_HOME_DIR; WCHAR wszAttrHomeDrive[] = DS_ATTR_HOME_DRIVE; WCHAR wszAttrLogonScript[] = DS_ATTR_LOGON_SCRIPT; WCHAR wszAttrProfilePath[] = DS_ATTR_PROFILE_PATH; WCHAR wszAttrWorkstations[]= DS_ATTR_WORKSTATIONS; WCHAR wszAttrParameters[] = DS_ATTR_PARAMETERS; WCHAR wszAttrLastLogon[] = DS_ATTR_LAST_LOGON; WCHAR wszAttrLastLogoff[] = DS_ATTR_LAST_LOGOFF; WCHAR wszAttrPasswordLastSet[] = DS_ATTR_PASSWORD_LAST_SET; WCHAR wszAttrAllowPasswordChange[] = DS_ATTR_ALLOW_PASSWORD_CHANGE; WCHAR wszAttrForcePasswordChange[] = DS_ATTR_FORCE_PASSWORD_CHANGE; WCHAR wszAttrLogonHours[] = DS_ATTR_LOGON_HOURS; WCHAR wszAttrBadPasswordCount[] = DS_ATTR_BAD_PASSWORD_COUNT; WCHAR wszAttrLogonCount[] = DS_ATTR_LOGON_COUNT; WCHAR wszAttrAccountFlags[] = DS_ATTR_ACCOUNT_FLAGS; WCHAR wszAttrAccountExpiry[] = DS_ATTR_ACCOUNT_EXPIRY; WCHAR wszAttrLmHash[] = DS_ATTR_LM_HASH; WCHAR wszAttrNtHash[] = DS_ATTR_NT_HASH; CHAR szAttrDn[] = DS_ATTR_DISTINGUISHED_NAME; DWORD dwScope = 0; PSTR pszDn = NULL; PWSTR pwszFilter = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwEntriesNum = 0; UserInfo *pUserInfo = NULL; PWSTR wszAttributesLevel1[] = { wszAttrSamAccountName, wszAttrFullName, wszAttrPrimaryGroup, wszAttrDescription, wszAttrComment, NULL }; PWSTR wszAttributesLevel2[] = { wszAttrComment, wszAttrCountryCode, wszAttrCodePage, NULL }; PWSTR wszAttributesLevel3[] = { wszAttrSamAccountName, wszAttrFullName, wszAttrObjectSid, wszAttrPrimaryGroup, wszAttrHomeDirectory, wszAttrHomeDrive, wszAttrLogonScript, wszAttrProfilePath, wszAttrWorkstations, wszAttrLastLogon, wszAttrLastLogoff, wszAttrPasswordLastSet, wszAttrAllowPasswordChange, wszAttrForcePasswordChange, wszAttrLogonHours, wszAttrBadPasswordCount, wszAttrLogonCount, wszAttrAccountFlags, NULL }; PWSTR wszAttributesLevel4[] = { wszAttrLogonHours, NULL }; PWSTR wszAttributesLevel5[] = { wszAttrSamAccountName, wszAttrFullName, wszAttrObjectSid, wszAttrPrimaryGroup, wszAttrHomeDirectory, wszAttrHomeDrive, wszAttrLogonScript, wszAttrProfilePath, wszAttrDescription, wszAttrWorkstations, wszAttrLastLogon, wszAttrLastLogoff, wszAttrLogonHours, wszAttrBadPasswordCount, wszAttrLogonCount, wszAttrPasswordLastSet, wszAttrAccountExpiry, wszAttrAccountFlags, NULL }; PWSTR wszAttributesLevel6[] = { wszAttrSamAccountName, wszAttrFullName, NULL }; PWSTR wszAttributesLevel7[] = { wszAttrSamAccountName, NULL }; PWSTR wszAttributesLevel8[] = { wszAttrFullName, NULL }; PWSTR wszAttributesLevel9[] = { wszAttrPrimaryGroup, NULL }; PWSTR wszAttributesLevel10[] = { wszAttrHomeDirectory, wszAttrHomeDrive, NULL }; PWSTR wszAttributesLevel11[] = { wszAttrLogonScript, NULL }; PWSTR wszAttributesLevel12[] = { wszAttrProfilePath, NULL }; PWSTR wszAttributesLevel13[] = { wszAttrDescription, NULL }; PWSTR wszAttributesLevel14[] = { wszAttrWorkstations, NULL }; PWSTR wszAttributesLevel16[] = { wszAttrAccountFlags, NULL }; PWSTR wszAttributesLevel17[] = { wszAttrAccountExpiry, NULL }; PWSTR wszAttributesLevel20[] = { wszAttrParameters, NULL }; PWSTR wszAttributesLevel21[] = { wszAttrLastLogon, wszAttrLastLogoff, wszAttrPasswordLastSet, wszAttrAccountExpiry, wszAttrAllowPasswordChange, wszAttrForcePasswordChange, wszAttrSamAccountName, wszAttrFullName, wszAttrHomeDirectory, wszAttrHomeDrive, wszAttrLogonScript, wszAttrProfilePath, wszAttrDescription, wszAttrWorkstations, wszAttrComment, wszAttrParameters, wszAttrObjectSid, wszAttrPrimaryGroup, wszAttrAccountFlags, wszAttrLogonHours, wszAttrBadPasswordCount, wszAttrLogonCount, wszAttrCountryCode, wszAttrCodePage, wszAttrLmHash, wszAttrNtHash, NULL }; PWSTR *pwszAttributes[] = { wszAttributesLevel1, wszAttributesLevel2, wszAttributesLevel3, wszAttributesLevel4, wszAttributesLevel5, wszAttributesLevel6, wszAttributesLevel7, wszAttributesLevel8, wszAttributesLevel9, wszAttributesLevel10, wszAttributesLevel11, wszAttributesLevel12, wszAttributesLevel13, wszAttributesLevel14, NULL, wszAttributesLevel16, wszAttributesLevel17, NULL, NULL, wszAttributesLevel20, wszAttributesLevel21 }; pAcctCtx = (PACCOUNT_CONTEXT)hUser; if (pAcctCtx == NULL || pAcctCtx->Type != SamrContextAccount) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } switch (level) { case 15: case 18: case 19: ntStatus = STATUS_INVALID_INFO_CLASS; break; default: ntStatus = STATUS_SUCCESS; } BAIL_ON_NTSTATUS_ERROR(ntStatus); pDomCtx = pAcctCtx->pDomCtx; pConnCtx = pDomCtx->pConnCtx; pwszBase = pDomCtx->pwszDn; dwError = LwWc16sToMbs(pAcctCtx->pwszDn, &pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, filterFormat, szAttrDn, pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch(pConnCtx->hDirectory, pwszBase, dwScope, pwszFilter, pwszAttributes[level - 1], FALSE, &pEntry, &dwEntriesNum); BAIL_ON_LSA_ERROR(dwError); if (dwEntriesNum == 0) { ntStatus = STATUS_INVALID_HANDLE; } else if (dwEntriesNum > 1) { ntStatus = STATUS_INTERNAL_ERROR; } BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = SamrSrvAllocateMemory((void**)&pUserInfo, sizeof(*pUserInfo)); BAIL_ON_NTSTATUS_ERROR(ntStatus); switch (level) { case 1: case 6: case 7: case 8: case 13: if (!(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_NAME_ETC) || !(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_ATTRIBUTES)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } break; case 2: if (!(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_LOCALE) || !(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_ATTRIBUTES)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } break; case 4: case 5: case 10: case 11: case 12: case 14: case 17: if (!(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_LOGONINFO) || !(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_ATTRIBUTES)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } break; case 3: case 9: case 16: case 20: case 21: if (!(pAcctCtx->dwAccessGranted & USER_ACCESS_GET_ATTRIBUTES)) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } break; } switch (level) { case 1: ntStatus = SamrFillUserInfo1(pEntry, pUserInfo); break; case 2: ntStatus = SamrFillUserInfo2(pEntry, pUserInfo); break; case 3: ntStatus = SamrFillUserInfo3(pAcctCtx, pEntry, pUserInfo); break; case 4: ntStatus = SamrFillUserInfo4(pEntry, pUserInfo); break; case 5: ntStatus = SamrFillUserInfo5(pEntry, pUserInfo); break; case 6: ntStatus = SamrFillUserInfo6(pEntry, pUserInfo); break; case 7: ntStatus = SamrFillUserInfo7(pEntry, pUserInfo); break; case 8: ntStatus = SamrFillUserInfo8(pEntry, pUserInfo); break; case 9: ntStatus = SamrFillUserInfo9(pEntry, pUserInfo); break; case 10: ntStatus = SamrFillUserInfo10(pEntry, pUserInfo); break; case 11: ntStatus = SamrFillUserInfo11(pEntry, pUserInfo); break; case 12: ntStatus = SamrFillUserInfo12(pEntry, pUserInfo); break; case 13: ntStatus = SamrFillUserInfo13(pEntry, pUserInfo); break; case 14: ntStatus = SamrFillUserInfo14(pEntry, pUserInfo); break; case 16: ntStatus = SamrFillUserInfo16(pEntry, pUserInfo); break; case 17: ntStatus = SamrFillUserInfo17(pEntry, pUserInfo); break; case 20: ntStatus = SamrFillUserInfo20(pEntry, pUserInfo); break; case 21: ntStatus = SamrFillUserInfo21(pAcctCtx, pEntry, pUserInfo); break; default: ntStatus = STATUS_INVALID_INFO_CLASS; } BAIL_ON_NTSTATUS_ERROR(ntStatus); *info = pUserInfo; cleanup: LW_SAFE_FREE_MEMORY(pszDn); LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntry) { DirectoryFreeEntries(pEntry, dwEntriesNum); } return ntStatus; error: if (pUserInfo) { SamrSrvFreeMemory(pUserInfo); } *info = NULL; goto cleanup; }
DWORD LocalFindObjectByName( HANDLE hProvider, PCSTR pszName, PCSTR pszDomainName, PDWORD pdwObjectClass, PWSTR* ppwszObjectDN ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; wchar16_t wszAttrNameObjectClass[] = LOCAL_DIR_ATTR_OBJECT_CLASS; wchar16_t wszAttrNameDN[] = LOCAL_DIR_ATTR_DISTINGUISHED_NAME; PWSTR wszAttrs[] = { &wszAttrNameObjectClass[0], &wszAttrNameDN[0], NULL }; DWORD dwNumAttrs = (sizeof(wszAttrs)/sizeof(wszAttrs[0])) - 1; PDIRECTORY_ENTRY pEntries = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; PCSTR pszFilterTemplate = LOCAL_DB_DIR_ATTR_SAM_ACCOUNT_NAME " = %Q" \ " AND " LOCAL_DB_DIR_ATTR_DOMAIN " = %Q"; PWSTR pwszFilter = NULL; PWSTR pwszObjectDN = NULL; DWORD dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplate, pszName, pszDomainName); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszAttrs, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries == 0) { dwError = LW_ERROR_NO_SUCH_OBJECT; } else if (dwNumEntries != 1) { dwError = LW_ERROR_DATA_ERROR; } BAIL_ON_LSA_ERROR(dwError); pEntry = &pEntries[0]; if (pEntry->ulNumAttributes != dwNumAttrs) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } dwError = LocalMarshalAttrToInteger( pEntry, &wszAttrNameObjectClass[0], &dwObjectClass); BAIL_ON_LSA_ERROR(dwError); dwError = LocalMarshalAttrToUnicodeString( pEntry, &wszAttrNameDN[0], &pwszObjectDN); BAIL_ON_LSA_ERROR(dwError); *pdwObjectClass = dwObjectClass; *ppwszObjectDN = pwszObjectDN; cleanup: LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } return dwError; error: *pdwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; *ppwszObjectDN = NULL; LW_SAFE_FREE_MEMORY(pwszObjectDN); goto cleanup; }
NTSTATUS SamrSrvQuerySecurity( IN handle_t hBinding, IN void *hObject, IN DWORD dwSecurityInfo, OUT PSAMR_SECURITY_DESCRIPTOR_BUFFER *ppSecDescBuf ) { PCSTR filterFormat = "%s=%Q"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PSAMR_GENERIC_CONTEXT pCtx = (PSAMR_GENERIC_CONTEXT)hObject; PDOMAIN_CONTEXT pDomCtx = NULL; PACCOUNT_CONTEXT pAcctCtx = NULL; PWSTR pwszDn = NULL; HANDLE hDirectory = NULL; PWSTR pwszBaseDn = NULL; DWORD dwScope = 0; WCHAR wszAttrSecDesc[] = DS_ATTR_SECURITY_DESCRIPTOR; CHAR szAttrDn[] = DS_ATTR_DISTINGUISHED_NAME; PSTR pszDn = NULL; PWSTR pwszFilter = NULL; PDIRECTORY_ENTRY pEntries = NULL; DWORD dwNumEntries = 0; PDIRECTORY_ENTRY pObjectEntry = NULL; POCTET_STRING pSecDescBlob = NULL; PSAMR_SECURITY_DESCRIPTOR_BUFFER pSecDescBuf = NULL; PWSTR wszAttributes[] = { wszAttrSecDesc, NULL }; /* * Only querying security descriptor on an account is allowed */ if (pCtx->Type == SamrContextAccount) { pAcctCtx = (PACCOUNT_CONTEXT)hObject; pDomCtx = pAcctCtx->pDomCtx; pwszDn = pAcctCtx->pwszDn; hDirectory = pDomCtx->pConnCtx->hDirectory; } else if (pCtx->Type == SamrContextConnect || pCtx->Type == SamrContextDomain) { ntStatus = STATUS_ACCESS_DENIED; } else { ntStatus = STATUS_INVALID_HANDLE; } BAIL_ON_NTSTATUS_ERROR(ntStatus); /* * 1) READ_CONTROL right is required to read a security descriptor * 2) Querying SACL part of the SD is not permitted over rpc */ if (!(pAcctCtx->dwAccessGranted & READ_CONTROL) || dwSecurityInfo & SACL_SECURITY_INFORMATION) { ntStatus = STATUS_ACCESS_DENIED; BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = LwWc16sToMbs(pwszDn, &pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, filterFormat, szAttrDn, pszDn); BAIL_ON_LSA_ERROR(dwError); dwError = DirectorySearch(hDirectory, pwszBaseDn, dwScope, pwszFilter, wszAttributes, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries == 0) { ntStatus = STATUS_INVALID_HANDLE; } else if (dwNumEntries > 1) { ntStatus = STATUS_INTERNAL_ERROR; } BAIL_ON_NTSTATUS_ERROR(ntStatus); pObjectEntry = &(pEntries[0]); dwError = DirectoryGetEntryAttrValueByName( pObjectEntry, wszAttrSecDesc, DIRECTORY_ATTR_TYPE_NT_SECURITY_DESCRIPTOR, &pSecDescBlob); BAIL_ON_LSA_ERROR(dwError); ntStatus = SamrSrvAllocateSecDescBuffer( &pSecDescBuf, (SECURITY_INFORMATION)dwSecurityInfo, pSecDescBlob); BAIL_ON_NTSTATUS_ERROR(ntStatus); *ppSecDescBuf = pSecDescBuf; cleanup: if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } LW_SAFE_FREE_MEMORY(pszDn); LW_SAFE_FREE_MEMORY(pwszFilter); if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: if (pSecDescBuf) { if (pSecDescBuf->pBuffer) { SamrSrvFreeMemory(pSecDescBuf->pBuffer); } SamrSrvFreeMemory(pSecDescBuf); } *ppSecDescBuf = NULL; goto cleanup; }
NTSTATUS SamrSrvLookupDomain( /* [in] */ handle_t hBinding, /* [in] */ CONNECT_HANDLE hConn, /* [in] */ UNICODE_STRING *domain_name, /* [out] */ SID **ppSid ) { CHAR szDnToken[] = "DC"; wchar_t wszFilter[] = L"%ws=%u AND %ws=\'%ws\'"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = 0; PCONNECT_CONTEXT pConnCtx = NULL; PWSTR pwszBase = NULL; WCHAR wszAttrObjectClass[] = DS_ATTR_OBJECT_CLASS; WCHAR wszAttrDomain[] = DS_ATTR_DOMAIN; WCHAR wszAttrObjectSID[] = DS_ATTR_OBJECT_SID; DWORD dwObjectClass = DS_OBJECT_CLASS_DOMAIN; WCHAR wszBuiltinDomainName[] = SAMR_BUILTIN_DOMAIN_NAME; PWSTR pwszDomainName = NULL; DWORD dwBaseLen = 0; DWORD dwScope = 0; PWSTR pwszFilter = NULL; DWORD dwFilterLen = 0; PWSTR wszAttributes[2]; PDIRECTORY_ENTRY pEntries = NULL; DWORD dwCount = 0; PDIRECTORY_ATTRIBUTE pAttr = NULL; PATTRIBUTE_VALUE pAttrVal = NULL; PSID pDomainSid = NULL; BAIL_ON_INVALID_PARAMETER(ppSid); BAIL_ON_INVALID_PARAMETER(domain_name); memset(wszAttributes, 0, sizeof(wszAttributes)); pConnCtx = (PCONNECT_CONTEXT)hConn; if (pConnCtx == NULL || pConnCtx->Type != SamrContextConnect) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } ntStatus = SamrSrvGetFromUnicodeString(&pwszDomainName, domain_name); BAIL_ON_NO_MEMORY(pwszDomainName); if (!wc16scasecmp(pwszDomainName, wszBuiltinDomainName)) { dwObjectClass = DS_OBJECT_CLASS_BUILTIN_DOMAIN; } dwBaseLen = domain_name->MaximumLength + ((sizeof(szDnToken) + 2) * sizeof(WCHAR)); dwFilterLen = (sizeof(wszAttrObjectClass) - 1) + 10 + (sizeof(wszAttrDomain) - 1) + domain_name->Length + sizeof(wszFilter); ntStatus = SamrSrvAllocateMemory(OUT_PPVOID(&pwszFilter), dwFilterLen); BAIL_ON_NTSTATUS_ERROR(ntStatus); if (sw16printfw(pwszFilter, dwFilterLen/sizeof(WCHAR), wszFilter, wszAttrObjectClass, dwObjectClass, wszAttrDomain, pwszDomainName) < 0) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NT_STATUS(ntStatus); } wszAttributes[0] = wszAttrObjectSID; wszAttributes[1] = NULL; dwError = DirectorySearch(pConnCtx->hDirectory, pwszBase, dwScope, pwszFilter, wszAttributes, FALSE, &pEntries, &dwCount); BAIL_ON_LSA_ERROR(dwError); if (dwCount == 1) { dwError = DirectoryGetEntryAttributeSingle(pEntries, &pAttr); BAIL_ON_LSA_ERROR(dwError); dwError = DirectoryGetAttributeValue(pAttr, &pAttrVal); BAIL_ON_LSA_ERROR(dwError); if (pAttrVal->Type == DIRECTORY_ATTR_TYPE_UNICODE_STRING) { ntStatus = SamrSrvAllocateSidFromWC16String( &pDomainSid, pAttrVal->data.pwszStringValue); BAIL_ON_NTSTATUS_ERROR(ntStatus); } else { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NTSTATUS_ERROR(ntStatus); } } else if (dwCount == 0) { ntStatus = STATUS_NO_SUCH_DOMAIN; BAIL_ON_NTSTATUS_ERROR(ntStatus); } else { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NTSTATUS_ERROR(ntStatus); } *ppSid = pDomainSid; cleanup: if (pwszBase) { SamrSrvFreeMemory(pwszBase); } if (pwszDomainName) { SamrSrvFreeMemory(pwszDomainName); } if (pwszFilter) { SamrSrvFreeMemory(pwszFilter); } if (pEntries) { DirectoryFreeEntries(pEntries, dwCount); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: if (pDomainSid) { SamrSrvFreeMemory(&pDomainSid); } *ppSid = NULL; goto cleanup; }
DWORD DirectoryAddObject( HANDLE hDirectory, PWSTR pwszObjectDN, DIRECTORY_MOD attributes[] ) { DWORD dwError = 0; PDIRECTORY_CONTEXT pContext = (PDIRECTORY_CONTEXT)hDirectory; PWSTR pwszBase = NULL; DWORD dwScope = 0; wchar_t wszFilterFmt[] = L"%ws='%ws'"; size_t sDnLen = 0; DWORD dwFilterLen = 0; PWSTR pwszFilter = NULL; WCHAR wszAttrDn[] = DIRECTORY_ATTR_DISTINGUISHED_NAME; WCHAR wszAttrObjectClass[] = DIRECTORY_ATTR_OBJECT_CLASS; PDIRECTORY_ENTRY pEntries = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; DWORD dwObjectClass = 0; PWSTR wszAttributes[] = { wszAttrDn, wszAttrObjectClass, NULL }; if (!pContext || !pContext->pProvider) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_DIRECTORY_ERROR(dwError); } dwError = LwWc16sLen(pwszObjectDN, &sDnLen); BAIL_ON_DIRECTORY_ERROR(dwError); dwFilterLen = ((sizeof(wszFilterFmt)/sizeof(wszFilterFmt[0])) - 1) + sizeof(wszAttrDn) + (sizeof(WCHAR) * sDnLen); dwError = DirectoryAllocateMemory(dwFilterLen, OUT_PPVOID(&pwszFilter)); BAIL_ON_DIRECTORY_ERROR(dwError); if (sw16printfw(pwszFilter, dwFilterLen, wszFilterFmt, wszAttrDn, pwszObjectDN) < 0) { dwError = LwErrnoToWin32Error(errno); BAIL_ON_DIRECTORY_ERROR(dwError); } dwError = DirectorySearch(hDirectory, pwszBase, dwScope, pwszFilter, wszAttributes, FALSE, &pEntries, &dwNumEntries); BAIL_ON_DIRECTORY_ERROR(dwError); if (dwNumEntries == 1) { pEntry = &(pEntries[0]); dwError = DirectoryGetEntryAttrValueByName( pEntry, wszAttrObjectClass, DIRECTORY_ATTR_TYPE_INTEGER, &dwObjectClass); BAIL_ON_DIRECTORY_ERROR(dwError); switch (dwObjectClass) { case DIR_OBJECT_CLASS_USER: dwError = ERROR_USER_EXISTS; break; case DIR_OBJECT_CLASS_LOCAL_GROUP: dwError = ERROR_ALIAS_EXISTS; break; default: dwError = ERROR_ALREADY_EXISTS; break; } BAIL_ON_DIRECTORY_ERROR(dwError); } else if (dwNumEntries > 1) { dwError = LW_ERROR_SAM_DATABASE_ERROR; BAIL_ON_DIRECTORY_ERROR(dwError); } dwError = pContext->pProvider->pProviderFnTbl->pfnDirectoryAdd( pContext->hBindHandle, pwszObjectDN, attributes); error: if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } DIRECTORY_FREE_MEMORY(pwszFilter); return dwError; }
NTSTATUS SamrSrvRemoveMemberFromForeignDomain( /* [in] */ handle_t hBinding, /* [in] */ DOMAIN_HANDLE hDomain, /* [in] */ PSID pSid ) { const DWORD dwAccessMask = ALIAS_ACCESS_REMOVE_MEMBER; const wchar_t wszDomainFilterFmt[] = L"%ws=%u"; const wchar_t wszFilterFmt[] = L"%ws=%u AND %ws='%ws'"; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PDOMAIN_CONTEXT pDomCtx = NULL; PCONNECT_CONTEXT pConnCtx = NULL; HANDLE hDirectory = NULL; DWORD i = 0; WCHAR wszAttrObjectClass[] = DS_ATTR_OBJECT_CLASS; WCHAR wszAttrObjectSid[] = DS_ATTR_OBJECT_SID; WCHAR wszAttrDomainName[] = DS_ATTR_DOMAIN; DWORD dwDomainObjectClass = DIR_OBJECT_CLASS_DOMAIN; DWORD dwDomainFilterLen = 0; PWSTR pwszDomainFilter = NULL; PWSTR pwszBase = NULL; DWORD dwScope = 0; PDIRECTORY_ENTRY pDomainEntries = NULL; DWORD dwNumDomainEntries = 0; PWSTR pwszDomainSid = NULL; PSID pDomainSid = NULL; PWSTR pwszDomainName = NULL; DWORD dwFilterLen = 0; PWSTR pwszFilter = NULL; DWORD dwObjectClass = DS_OBJECT_CLASS_LOCAL_GROUP; PDIRECTORY_ENTRY pEntries = NULL; DWORD dwEntriesNum = 0; PWSTR pwszAliasSid = NULL; PSID pAliasSid = NULL; DWORD dwRid = 0; ACCOUNT_HANDLE hAlias = NULL; PACCOUNT_CONTEXT pAcctCtx = NULL; PWSTR wszAttributes[] = { wszAttrObjectSid, NULL }; pDomCtx = (PDOMAIN_CONTEXT)hDomain; if (pDomCtx == NULL || pDomCtx->Type != SamrContextDomain) { ntStatus = STATUS_INVALID_HANDLE; BAIL_ON_NTSTATUS_ERROR(ntStatus); } pConnCtx = pDomCtx->pConnCtx; pwszDomainName = pDomCtx->pwszDomainName; hDirectory = pConnCtx->hDirectory; /* * Get the local domain SID and make sure we're not trying to * remove one of well-known SIDs from given domain */ dwDomainFilterLen = ((sizeof(wszAttrObjectClass)/sizeof(WCHAR)) - 1) + 10 + (sizeof(wszDomainFilterFmt)/ sizeof(wszDomainFilterFmt[0])); dwError = LwAllocateMemory(dwDomainFilterLen * sizeof(*pwszDomainFilter), OUT_PPVOID(&pwszDomainFilter)); BAIL_ON_LSA_ERROR(dwError); if (sw16printfw(pwszDomainFilter, dwDomainFilterLen, wszDomainFilterFmt, wszAttrObjectClass, dwDomainObjectClass) < 0) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = DirectorySearch(hDirectory, pwszBase, dwScope, pwszDomainFilter, wszAttributes, FALSE, &pDomainEntries, &dwNumDomainEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumDomainEntries != 1) { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = DirectoryGetEntryAttrValueByName( &(pDomainEntries[0]), wszAttrObjectSid, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszDomainSid); BAIL_ON_LSA_ERROR(dwError); ntStatus = RtlAllocateSidFromWC16String(&pDomainSid, pwszDomainSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); if (SamrSrvIsBuiltinAccount(pDomainSid, pSid)) { ntStatus = STATUS_SPECIAL_ACCOUNT; BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwFilterLen = ((sizeof(wszAttrObjectClass)/sizeof(WCHAR)) - 1) + 10 + ((sizeof(wszAttrDomainName)/sizeof(WCHAR)) - 1) + (wc16slen(pwszDomainName) + 1) + (sizeof(wszFilterFmt)/sizeof(wszFilterFmt[0])); dwError = LwAllocateMemory(dwFilterLen * sizeof(*pwszFilter), OUT_PPVOID(&pwszFilter)); BAIL_ON_LSA_ERROR(dwError); if (sw16printfw(pwszFilter, dwFilterLen, wszFilterFmt, wszAttrObjectClass, dwObjectClass, wszAttrDomainName, pwszDomainName) < 0) { ntStatus = LwErrnoToNtStatus(errno); BAIL_ON_NTSTATUS_ERROR(ntStatus); } dwError = DirectorySearch(hDirectory, pwszBase, dwScope, pwszFilter, wszAttributes, FALSE, &pEntries, &dwEntriesNum); BAIL_ON_LSA_ERROR(dwError); /* * Attempt to remove the SID from any alias it might be a member of */ for (i = 0; i < dwEntriesNum; i++) { PDIRECTORY_ENTRY pEntry = &(pEntries[i]); dwError = DirectoryGetEntryAttrValueByName( pEntry, wszAttrObjectSid, DIRECTORY_ATTR_TYPE_UNICODE_STRING, &pwszAliasSid); BAIL_ON_LSA_ERROR(dwError); ntStatus = RtlAllocateSidFromWC16String(&pAliasSid, pwszAliasSid); BAIL_ON_NTSTATUS_ERROR(ntStatus); dwRid = pAliasSid->SubAuthority[pAliasSid->SubAuthorityCount - 1]; ntStatus = SamrSrvOpenAccount(hBinding, hDomain, dwAccessMask, dwRid, DS_OBJECT_CLASS_LOCAL_GROUP, &hAlias); BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = SamrSrvDeleteAliasMember(hBinding, hAlias, pSid); if (ntStatus == STATUS_NO_SUCH_MEMBER || ntStatus == STATUS_MEMBER_NOT_IN_ALIAS) { /* Member is not in this alias so juts ignore it and try another one */ ntStatus = STATUS_SUCCESS; } BAIL_ON_NTSTATUS_ERROR(ntStatus); ntStatus = SamrSrvClose(hBinding, &hAlias); BAIL_ON_NTSTATUS_ERROR(ntStatus); RTL_FREE(&pAliasSid); } cleanup: LW_SAFE_FREE_MEMORY(pwszDomainFilter); LW_SAFE_FREE_MEMORY(pwszFilter); if (pDomainEntries) { DirectoryFreeEntries(pDomainEntries, dwNumDomainEntries); } RTL_FREE(&pDomainSid); if (pEntries) { DirectoryFreeEntries(pEntries, dwEntriesNum); } if (hAlias) { pAcctCtx = (PACCOUNT_CONTEXT)hAlias; hAlias = NULL; SamrSrvAccountContextFree(pAcctCtx); } RTL_FREE(&pAliasSid); if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }