Using IExchangeModifyTable to Modify Public Folder Access
| Nik Okuntseff |
MS Exchange Server Programming |
Using IExchangeModifyTable to Modify Public Folder Access
Second way of dealing with public folder ACLs is using the IExchangeModifyTable
interface. Using this approach you obtain ACL in a form of a MAPI table.
You can manipulate this table (for example, by inserting or modifying rows)
and then save your changes.
Where ACL Data Is Stored?
You may wonder where public folder ACL data is stored. It is stored
in PR_ACL_DATA property of the folder object. It is a binary object. Being
binary reminds of a Windows NT DACL, but instead of security identifiers
public folder ACL deals with MAPI ENTRYIDs, which are usually bigger in
size.
Reading Public Folder ACL with IExchangeModifyTable
The following sample (Security/IExchangeModifyTableDump) dumps contents
of a public folder ACL:
#include <afxwin.h>
#include <edk.h>
int main()
{
/*
* Algorithm:
* 1. Open the folder.
* 2. Obtain IExchangeModifyTable.
* 3. Get ACL table with data.
* 4. Scan the table and dump member
names with their rights.
*/
char * pszFolder = "@PR_IPM_SUBTREE_ENTRYID\\All
Public Folders\\MyPublicFolder";
HRESULT hr;
LPMAPISESSION pSession = NULL;
// Initialize MAPI
hr = MAPIInitialize(NULL);
if (FAILED(hr)) throw -1;
// Obtain MAPI session
hr = MAPILogonEx(0, // Handle
to parent window
"MS Exchange Settings", // Profile name
NULL, // Password
MAPI_NEW_SESSION |
MAPI_EXTENDED |
MAPI_LOGON_UI, // Logon flags
&pSession); // Resulting MAPI
session
if (FAILED(hr)) throw -1;
// Open Exchange public message store
LPMDB pPublicMsgStore = NULL;
hr = HrOpenExchangePublicStore(pSession, &pPublicMsgStore);
if (FAILED(hr)) throw -1;
// Open the folder
LPMAPIFOLDER pFolder = NULL;
hr = HrMAPIOpenFolderEx(pPublicMsgStore,
'\\',
pszFolder,
&pFolder);
if (FAILED(hr)) throw -1;
// Try to open IExchangeModifyTable
LPEXCHANGEMODIFYTABLE pExchangeTable = NULL;
hr = pFolder->OpenProperty(PR_ACL_TABLE,
(LPGUID) &IID_IExchangeModifyTable,
0,
MAPI_DEFERRED_ERRORS,
(LPUNKNOWN *) &pExchangeTable);
if (FAILED(hr)) throw -1;
// Get the table
LPMAPITABLE pAclDataTable = NULL;
hr = pExchangeTable->GetTable(0, &pAclDataTable);
if (FAILED(hr)) throw -1;
// Get row count
ULONG ulRows = 0;
hr = pAclDataTable->GetRowCount(0, &ulRows);
if (FAILED(hr)) throw -1;
assert(ulRows > 0);
// Get all rows
SRowSet * pRowSet = NULL;
hr = pAclDataTable->QueryRows(ulRows, 0, &pRowSet);
assert(ulRows == pRowSet->cRows);
SRow row;
for (ULONG ul = 0; ul < ulRows; ul++)
{
row = pRowSet->aRow[ul];
// Dump member name
for (ULONG ulIndex = 0;
ulIndex < row.cValues; ulIndex++)
{
if (PR_MEMBER_NAME == row.lpProps[ulIndex].ulPropTag)
{
char * pszMemberName = row.lpProps[ulIndex].Value.lpszA;
printf("%s", pszMemberName);
break;
}
}
// Dump member rights
for (ulIndex = 0; ulIndex
< row.cValues; ulIndex++)
{
if (PR_MEMBER_RIGHTS == row.lpProps[ulIndex].ulPropTag)
{
LONG lRights = row.lpProps[ulIndex].Value.l;
printf(" rights: 0x%08X\n", lRights);
break;
}
}
}
// Cleanup
if (pRowSet)
MAPIFreeBuffer(pRowSet);
if (pAclDataTable)
pAclDataTable->Release();
if (pExchangeTable)
pExchangeTable->Release();
if (pFolder)
pFolder->Release();
if (pPublicMsgStore)
pPublicMsgStore->Release();
if (pSession)
pSession->Release();
return 0;
}
A few comments about the code above. Notice that I obtain IExchangeModifyTable
interface via the IMAPIFolder::OpenProperty call requesting PR_ACL_TABLE.
This property is of type PT_OBJECT. However, if you examine properties
of the folder with a tool such as mdbvu32.exe, it may not be there. For
example, for a folder I am experimenting with now PR_ACL_TABLE is not available,
but PR_ACL_DATA is.
This is how these properties are defined in EdkMdb.h:
#define pidExchangeXmitReservedMin 0x3FE0
#define PR_ACL_TABLE PROP_TAG( PT_OBJECT, pidExchangeXmitReservedMin)
#define PR_ACL_DATA PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin)
Mdbvu32.exe does not know their names and displays PR_ACL_DATA as 0x3FE0.
It turns out that it is still possible to use the OpenProperty specifying
PR_ACL_DATA. Exchange creates IExchangeModifyTable interface and gives
it back to us for use. Binary table data is actually stored in PR_ACL_DATA.
Using IExchangeModifyTable interface is just a more convenient way of working
with this data. Having obtained the interface with the OpenProperty call
I then use its GetTable method to get a MAPI table filled with data. I
scan this table looking for member names and their access rights.
If you run this code you will see that the Default and Anonymous accounts
actually have their names listed in the table. Remember that when we were
using the IExchangeFolderACLs the names and ENTRYIDs were NULLs. This is
a nice advantage of using IExchangeModifyTable interface.
Modifying Public Folder ACL with IExchangeModifyTable
Modifying ACL with IExchangeModifyTable is tricky. If you are trying
to accomplish this - be prepared to spend some time guessing how it is
supposed to work. IExchangeFolderACLs interface is implemented on top of
IExchangeModifyTable. If you examine CFolderACLs class implementation in
aclclsf.cpp file in your build environment samples\dbmsg\Exchange\libsrc\aclcls
project, you will see that for yourself. Apparently, it was designed to
simplify working with IExchangeModifyTable. Pay attention to comments,
they reveal important details about how IExchangeModifyTable is supposed
to be used. For example, you need to drop PR_MEMBER_NAME property when
modifying the table. I have spent a few hours trying to modify a single
row in the table with no luck (ERROR_INVALID_PARAMETER was returned by
the ModifyTable method). Apparently, I was doing something wrong. Anyway,
the best algorithm I could suggest here now would be as follows: study
libsrc code and do it as they do.
[ Contents |
Home
]
Send comments and suggestions to niko@wrconsulting.com
Copyright © 1997-1998 by Nik Okuntseff
|