//--acledit.cpp----------------------------------------------------------------
//
// Folder ACLs editing utility.
//
// Copyright (C) Microsoft Corp., 1986-1996. All rights reserved.
//
//-----------------------------------------------------------------------------
//
// Begin program documentation
//
#if0
Command line arguments: See Usage(), or invoke acledit.exe with no command
line arguments to get a usage note.
#endif
//
// End program documentation
//
#include "edk.h"
#include "errno.h"
#include "acledit.h"
//
// Enumeration, structure, and other type definitions
//
// ACLs editing commands:
enum EDITCMD// ec
{
EDITCMD_LIST,
EDITCMD_INSERT,
EDITCMD_DELETE,
EDITCMD_MODIFY,
EDITCMD_HELP,
EDITCMD_INVALID
};
structRIGHTSINFO// ri
{
LPSTRpszKeyWord;
ULONGcchKeyWord;
LONGlRights;
};
//
// Forward function declarations.
//
static
BOOL
bDoDelete(VOID);
static
BOOL
bDoInsert(VOID);
static
BOOL
bDoList(VOID);
static
BOOL
bDoModify(VOID);
static
BOOL
bParseCmdLine(
IN INT argc,
IN CHAR * argv[]
);
static
BOOL
bParseRightsLst(VOID);
static
VOID
DoHelp(VOID);
static
VOID
EventLogHexErrorMsg(
INDWORDdwEvent,
INHRESULThr
);
static
VOID
PrintRightsString(
INLONGlRights
);
static
VOID
PrintErr(
INCHAR *Format
...
);
static
VOID
Usage(VOID);
//
// Static storage
//
// Rights information array. This is layed out in a specific manner, with
// all single bit rights first. The order should not be changed. The
// manifest constant NONEINDX is used to limit lookup of keywords to the
// range of single bit values, since the other keywords are special cases.
staticRIGHTSINFOria[] =
{
"ReadAny", sizeof("ReadAny") - 1, frightsReadAny,
"Create", sizeof("Create") - 1, frightsCreate,
"EditOwned", sizeof("EditOwned") - 1, frightsEditOwned,
"DeleteOwned", sizeof("DeleteOwned") - 1, frightsDeleteOwned,
"EditAny", sizeof("EditAny") - 1, frightsEditAny,
"DeleteAny", sizeof("DeleteAny") - 1, frightsDeleteAny,
"CreateSubfolder", sizeof("CreateSubfolder") - 1, frightsCreateSubfolder,
"Owner", sizeof("Owner") - 1, frightsOwner,
"Contact", sizeof("Contact") - 1, frightsContact,
"None", sizeof("None") - 1, rightsNone,
"ReadOnly", sizeof("ReadOnly") - 1, rightsReadOnly,
"ReadWrite", sizeof("ReadWrite") - 1, rightsReadWrite,
"All", sizeof("All") - 1, rightsAll
};
#defineNONEINDX9
staticLPSTRpszProfile =NULL;
staticLPSTRpszStore =NULL;
staticLPSTRpszFolder =NULL;
staticLPSTRpszRights =NULL;
staticLPSTRpszUser =NULL;
staticBOOLfInboxArgFnd =FALSE;
staticEDITCMDEditCmd =EDITCMD_INVALID;
staticBOOLfPositionFnd =FALSE;
staticLONGlCursor = 0;
staticLONGlRights =0;
staticLPMAPISESSIONlpSession =NULL;
staticLPMDBlpStore =NULL;
staticULONGcbEIDStore = 0;
staticLPENTRYIDlpEIDStore =NULL;
staticULONGcbEIDFolder = 0;
staticLPENTRYIDlpEIDFolder =NULL;
staticLPFOLDERACLSlpFolderACLs =NULL;
// Command line argument flags, and array used by
// _HrExpandCommandLineArgument():
staticCHARszProfileArg[] ="profile";
staticCHARszStoreArg[] ="store";
staticCHARszFolderArg[] ="folder";
staticCHARszInboxArg[] ="inbox";
staticCHARszListArg[] ="list";
staticCHARszInsertArg[] ="insert";
staticCHARszModifyArg[] ="modify";
staticCHARszDeleteArg[] ="delete";
staticCHARszPositionArg[] ="position";
staticCHARszRightsArg[] ="rights";
staticCHARszUserArg[] ="user";
staticCHARszHelpArg[] ="help";
staticCHARszQuestionArg[] ="?";
staticCHAR *rgpszArgArray[] ={
szProfileArg,
szStoreArg,
szFolderArg,
szInboxArg,
szListArg,
szInsertArg,
szModifyArg,
szDeleteArg,
szPositionArg,
szRightsArg,
szUserArg,
szHelpArg,
szQuestionArg
};
staticULONGcErrs =0;
//
// Functions
//
// $--bDoDelete----------------------------------------------------------------
//
// DESCRIPTION:Execute the DELETE command.
//
// INPUT:None.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL
bDoDelete(VOID) // RETURNS: BOOL
{
HRESULThr =NOERROR;
BOOLbrc =FALSE;
LONGlCurCursor =0;
DEBUGPRIVATE("bDoDelete()\n");
hr = lpFolderACLs->HrSeek(lCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_SEEK_FAILED, hr);
goto cleanup;
}
// We do prior check of cursor location to be able to cleanly specify
// the error.
hr = lpFolderACLs->HrTell(&lCurCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_TELL_FAILED, hr);
goto cleanup;
}
if (lCurCursor == ACL_PAST_END)
{
PrintErr("ACL at position END does not exist");
goto cleanup;
}
hr = lpFolderACLs->HrDelete();
if (FAILED(hr))
{
PrintErr("Deletion failed. If the ACL specified is the default ACL or\n"
"is the ACL for the current user on a public folder, "
"it may not be deleted");
cErrs--;
EventLogHexErrorMsg(ACLEDIT_DELETE_FAILED, hr);
goto cleanup;
}
brc = TRUE;
cleanup:
return brc;
}
// $--bDoInsert----------------------------------------------------------------
//
// DESCRIPTION:Execute the INSERT command.
//
// INPUT:None.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL
bDoInsert(VOID) // RETURNS: BOOL
{
LPSPropValueaPropVals = NULL;
BOOLbrc =FALSE;
ULONGcbEIDUser =0;
HRESULThr =NOERROR;
ULONGi =0;
LONGlCurCursor =0;
LONGlNewRights =0;
LPADRBOOKlpAdrBook =NULL;
LPADRENTRYlpAdrEntry = NULL;
LPADRLISTlpAdrList =NULL;
LPENTRYIDlpEIDUser =NULL;
LPSTRlpszDisplayName =NULL;
DEBUGPRIVATE("bDoInsert()\n");
hr = lpFolderACLs->HrSeek(lCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_SEEK_FAILED, hr);
goto cleanup;
}
// We do prior check of cursor location to be able to cleanly specify
// the error.
hr = lpFolderACLs->HrTell(&lCurCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_TELL_FAILED, hr);
goto cleanup;
}
// Open the address book and get the user entryid.
hr = lpSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &lpAdrBook);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_OPENADDRESSBOOK_FAILED, hr);
goto cleanup;
}
hr = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID FAR *)&lpAdrList);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_ALLOCATION_FAILED, hr);
goto cleanup;
}
lpAdrEntry = lpAdrList->aEntries;
lpAdrList->cEntries = 1;
lpAdrEntry->ulReserved1 =0;
lpAdrEntry->cValues =1;
lpAdrEntry->rgPropVals =NULL;
hr = MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID FAR *)&aPropVals);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_ALLOCATION_FAILED, hr);
goto cleanup;
}
lpAdrEntry->rgPropVals =aPropVals;
aPropVals[0].ulPropTag =PR_DISPLAY_NAME;
aPropVals[0].Value.lpszA =NULL;
hr = MAPIAllocateMore(strlen(pszUser) + 1,
lpAdrEntry->rgPropVals,
(LPVOID FAR *)&lpAdrEntry->rgPropVals[0].Value.lpszA);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_ALLOCATION_FAILED, hr);
goto cleanup;
}
strcpy(lpAdrEntry->rgPropVals[0].Value.lpszA, pszUser);
hr = lpAdrBook->ResolveName(0, 0, NULL, lpAdrList);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_RESOLVENAME_FAILED, hr);
goto cleanup;
}
// Pick up ptr values again, assuming there was reallocation.
lpAdrEntry = lpAdrList->aEntries;
aPropVals =lpAdrEntry->rgPropVals;
for (i = 0; i < lpAdrEntry->cValues; i++)
{
if (aPropVals[i].ulPropTag == PR_ENTRYID)
{
cbEIDUser = aPropVals[i].Value.bin.cb;
lpEIDUser = (LPENTRYID)aPropVals[i].Value.bin.lpb;
break;
}
}
for (i = 0; i < lpAdrEntry->cValues; i++)
{
if (aPropVals[i].ulPropTag == PR_DISPLAY_NAME)
{
lpszDisplayName = aPropVals[i].Value.lpszA;
break;
}
}
if (lpEIDUser == NULL || lpszDisplayName == NULL)
{
hr = MAPI_E_NOT_FOUND;
EventLogHexErrorMsg(ACLEDIT_RESOLVENAME_FAILED, hr);
goto cleanup;
}
// Finally do the insert.
hr = lpFolderACLs->HrInsert(lRights,
lpszDisplayName,
cbEIDUser,
lpEIDUser,
&lNewRights);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_INSERT_FAILED, hr);
if (hr == E_FAIL)
{
PrintErr("Insertion failed. "
"If ACL for user already exists, use modify");
cErrs--;
}
else
{
PrintErr("Insertion failed");
cErrs--;
}
goto cleanup;
}
// If the rights obtained are not exactly what is expected (which due to
// certain Exchange vagaries may be the case), the modified rights
// will be printed out.
if (lRights != lNewRights)
{
printf("Rights actually set are '");
PrintRightsString(lNewRights);
printf("'\n\n");
}
brc = TRUE;
cleanup:
FREEPADRLIST(lpAdrList);
ULRELEASE(lpAdrBook);
return brc;
}
// $--bDoList------------------------------------------------------------------
//
// DESCRIPTION:Execute the LIST command.
//
// INPUT:None.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
//---------------------------------------------------------------------------
BOOL
bDoList(VOID) // RETURNS: BOOL
{
HRESULThr =NOERROR;
BOOLbrc =FALSE;
HANDLEhConsole =GetStdHandle(STD_OUTPUT_HANDLE);
LONGlCurCursor =0;
DEBUGPRIVATE("bDoList()\n");
if (!fPositionFnd)
lCursor = 0;
hr = lpFolderACLs->HrSeek(lCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_SEEK_FAILED, hr);
goto cleanup;
}
// Check for empty table or invalid cursor position.
hr = lpFolderACLs->HrTell(&lCurCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_TELL_FAILED, hr);
goto cleanup;
}
if (pszStore == NULL)
pszStore = "default";
if (!fPositionFnd)
{
printf("Listing of ACL table in folder \\%s in %s store:\n\n",
pszFolder, pszStore);
}
else if (lCurCursor != ACL_PAST_END)
{
printf("Listing of ACL table record %d in folder \\%s in %s store:\n\n",
lCurCursor, pszFolder, pszStore);
}
if (lCurCursor == ACL_PAST_END)
{
if (fPositionFnd)
{
PrintErr("ACL at position %d does not exist", lCursor);
}
else
{
printf("ACL table is empty.\n");
brc = TRUE;
}
goto cleanup;
}
while (TRUE)
{
ULONGcbentryid;
LONGlRights;
LPSTRlpszDisplayName =NULL;
LPENTRYIDlpentryid =NULL;
hr = lpFolderACLs->HrGet(&lRights,
&lpszDisplayName,
&cbentryid,
&lpentryid);
if (FAILED(hr))
{
HRESULThrSaved = hr;
hr = lpFolderACLs->HrTell(&lCurCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_TELL_FAILED, hr);
goto cleanup;
}
if (lCurCursor != ACL_PAST_END || hrSaved != E_FAIL)
{
EventLogHexErrorMsg(ACLEDIT_GET_FAILED, hrSaved);
goto cleanup;
}
break;
}
else
{
// Print listing:
printf("For record at cursor position %d:\n\n", lCurCursor);
printf(" User Name is '%s'\n", lpszDisplayName);
printf(" Rights are '");
PrintRightsString(lRights);
printf("'\n\n");
lCurCursor++;
}
// Clean up allocations:
MAPIFREEBUFFER(lpszDisplayName);
MAPIFREEBUFFER(lpentryid);
// Only dump one record if cursor position was specified.
if (fPositionFnd)
break;
}
brc = TRUE;
cleanup:
return brc;
}
// $--bDoModify----------------------------------------------------------------
//
// DESCRIPTION:Execute the MODIFY command.
//
// INPUT:None.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL
bDoModify(VOID) // RETURNS: BOOL
{
HRESULThr =NOERROR;
BOOLbrc =FALSE;
LONGlCurCursor =0;
LONGlNewRights =0;
DEBUGPRIVATE("bDoModify()\n");
hr = lpFolderACLs->HrSeek(lCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_SEEK_FAILED, hr);
goto cleanup;
}
// We do prior check of cursor location to be able to cleanly specify
// the error.
hr = lpFolderACLs->HrTell(&lCurCursor);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_TELL_FAILED, hr);
goto cleanup;
}
if (lCurCursor == ACL_PAST_END)
{
PrintErr("ACL at position END does not exist");
goto cleanup;
}
hr = lpFolderACLs->HrModify(lRights, &lNewRights);
if (FAILED(hr))
{
PrintErr("Modification failed");
cErrs--;
EventLogHexErrorMsg(ACLEDIT_MODIFY_FAILED, hr);
goto cleanup;
}
// If the rights obtained are not exactly what is expected (which due to
// certain Exchange vagaries may be the case), the modified rights
// will be printed out. For instance the Owner right is always retained
// for the current user ACL on a public folder, and setting EditAny will
// also cause EditOwned to be set.
if (lRights != lNewRights)
{
printf("Rights actually set are '");
PrintRightsString(lNewRights);
printf("'\n\n");
}
brc = TRUE;
cleanup:
return brc;
}
// $--bParseCmdLine------------------------------------------------------------
//
// DESCRIPTION: Parse the command line.
//
// INPUT:
//
//[argc]-- Count of arguments from command line.
//[argv]-- Array of arguments from command line.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL
bParseCmdLine(// RETURNS: BOOL
IN INT argc, // argument count
IN CHAR * argv[] // array of arguments
)
{
BOOL bRetVal = FALSE;
HRESULThr =NOERROR;
CHAR *pszArgData =NULL;
CHAR *pszFlagName =NULL;
DEBUGPRIVATE("bParseCmdLine()\n");
argc--;// Get rid of command argument.
argv++;
if (argc == 0)
goto cleanup;
while (argc > 0)
{
hr =_HrExpandCommandLineArgument(
*argv,
rgpszArgArray,
sizeof(rgpszArgArray)/sizeof(rgpszArgArray[0]),
NULL,
&pszFlagName,
&pszArgData
);
if (FAILED(hr))
{
PrintErr("Invalid command line argument");
goto cleanup;
}
if (pszFlagName == szProfileArg)
{
if (pszProfile != NULL)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
pszProfile = pszArgData;
}
else if (pszFlagName == szStoreArg)
{
if (pszStore != NULL)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
pszStore = pszArgData;
}
else if (pszFlagName == szFolderArg)
{
if (pszFolder != NULL)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
pszFolder = pszArgData;
}
else if (pszFlagName == szInboxArg)
{
// Note that you can put "/inbox" on the cmd line as many times
// as you like without creating a problem! :-)
if (pszStore != NULL || pszFolder != NULL)
{
PrintErr("Conflicting command line arguments");
goto cleanup;
}
if (pszArgData != NULL)
{
PrintErr("The /%s argument does not take a value", szInboxArg);
goto cleanup;
}
fInboxArgFnd = TRUE;
}
else if (pszFlagName == szListArg)
{
if (EditCmd != EDITCMD_INVALID)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
if (pszArgData != NULL)
{
PrintErr("The /%s argument does not take a value", szListArg);
goto cleanup;
}
EditCmd = EDITCMD_LIST;
}
else if (pszFlagName == szInsertArg)
{
if (EditCmd != EDITCMD_INVALID)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
if (pszArgData != NULL)
{
PrintErr("The /%s argument does not take a value",szInsertArg);
goto cleanup;
}
EditCmd = EDITCMD_INSERT;
}
else if (pszFlagName == szModifyArg)
{
if (EditCmd != EDITCMD_INVALID)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
if (pszArgData != NULL)
{
PrintErr("The /%s argument does not take a value",szInsertArg);
goto cleanup;
}
EditCmd = EDITCMD_MODIFY;
}
else if (pszFlagName == szDeleteArg)
{
if (EditCmd != EDITCMD_INVALID)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
if (pszArgData != NULL)
{
PrintErr("The /%s argument does not take a value",szDeleteArg);
goto cleanup;
}
EditCmd = EDITCMD_DELETE;
}
else if (pszFlagName == szPositionArg)
{
LPSTRpszValue = pszArgData;
if (fPositionFnd)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
if (pszValue == NULL || *pszValue == '\0')
{
PrintErr("The /%s argument requires a value", szPositionArg);
goto cleanup;
}
if (!_stricmp(pszValue, "END"))
{
lCursor = RULE_PAST_END;
}
else
{
errno = 0;
lCursor = strtol(pszValue, (CHAR **)NULL, 10);
if ((lCursor == LONG_MAX || lCursor == LONG_MIN) &&
errno == ERANGE)
{
PrintErr("Command line argument '%s' is invalid", *argv);
goto cleanup;
}
}
fPositionFnd = TRUE;
}
else if (pszFlagName == szRightsArg)
{
if (pszRights != NULL)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
pszRights = pszArgData;
if (pszRights == NULL || *pszRights == '\0')
{
PrintErr("The /%s argument requires a value", szRightsArg);
goto cleanup;
}
if (!bParseRightsLst())
goto cleanup;
}
else if (pszFlagName == szUserArg)
{
if (pszUser != NULL)
{
PrintErr("Duplicate command line arguments");
goto cleanup;
}
pszUser = pszArgData;
if (pszUser == NULL || *pszUser == '\0')
{
PrintErr("The /%s argument requires a value", szRightsArg);
goto cleanup;
}
}
else if (pszFlagName == szHelpArg||
pszFlagName == szQuestionArg)
{
EditCmd = EDITCMD_HELP;
// If we encounter /help or /?, we pretty much ignore everything
// else and produce a help msg.
bRetVal = TRUE;
goto cleanup;
}
else
{
PrintErr("Command line argument '%s' is invalid", *argv);
goto cleanup;
}
argc--;
argv++;
}
// Check that all args needed have been provided.
if (pszProfile == NULL)
{
PrintErr("Command line must specify %s argument", szProfileArg);
goto cleanup;
}
if (!fInboxArgFnd &&
(pszStore == NULL || *pszStore == '\0'||
pszFolder == NULL || *pszFolder == '\0'))
{
PrintErr("Command line must specify %s or %s and %s arguments",
szInboxArg, szStoreArg, szFolderArg);
goto cleanup;
}
if (EditCmd == EDITCMD_INVALID)
{
PrintErr("Command line must specify a command argument");
goto cleanup;
}
else if (EditCmd != EDITCMD_LIST && EditCmd != EDITCMD_INSERT)
{
if (!fPositionFnd)
{
PrintErr("Command argument specified requires %s argument",
szPositionArg);
goto cleanup;
}
}
if (EditCmd == EDITCMD_INSERT)
{
if (!fPositionFnd)
{
// Defaults to end of list.
fPositionFnd =TRUE;
lCursor =ACL_PAST_END;
}
if (pszRights == NULL)
{
PrintErr("Insert command requires %s argument", szRightsArg);
goto cleanup;
}
else if (pszUser == NULL)
{
PrintErr("Insert command requires %s argument", szUserArg);
goto cleanup;
}
}
else if (EditCmd == EDITCMD_MODIFY)
{
if (pszRights == NULL)
{
PrintErr("Modify command requires %s argument", szRightsArg);
goto cleanup;
}
}
else
{
if (pszRights != NULL)
{
PrintErr("A %s argument is only used with the insert or modify "
"command", szRightsArg);
goto cleanup;
}
else if (pszUser != NULL)
{
PrintErr("A %s argument is only used with the insert command",
szUserArg);
goto cleanup;
}
}
bRetVal = TRUE;
cleanup:
return bRetVal;
}
// $--bParseRightsLst----------------------------------------------------------
//
// DESCRIPTION:Parse the rights list, storing the result in the global lRights.
//
// RETURNS:TRUE on success; FALSE otherwise.
//
// Notes:The rights keywords are case insensitive, but otherwise must
//match exactly. There is no checking for keyword redundancy or
//conflict.
//-----------------------------------------------------------------------------
BOOL
bParseRightsLst(VOID)
{
BOOLbrc =FALSE;
ULONGcch =0;
ULONGi =0;
CHAR *pchBegin =pszRights;
CHAR *pchEnd =NULL;
while (*pchBegin != '\0')
{
while (isspace(*pchBegin))
pchBegin++;
pchEnd = pchBegin;
do
{
pchEnd++;
}while (!isspace(*pchEnd) && *pchEnd != '\0');
cch = pchEnd - pchBegin;
brc = FALSE;
for (i = 0; i < sizeof(ria)/sizeof(ria[0]); i++)
{
if (cch == ria[i].cchKeyWord&&
!memicmp(pchBegin, ria[i].pszKeyWord, cch))
{
lRights |= ria[i].lRights;
brc = TRUE;
break;
}
}
if (!brc)
{
PrintErr("Invalid keyword '%.*s' in the rights list",
cch, pchBegin);
goto cleanup;
}
pchBegin = pchEnd;
}
cleanup:
return brc;
}
// $--DoHelp------------------------------------------------------------------
//
// DESCRIPTION:Execute the HELP command.
//
// INPUT:None.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
VOID
DoHelp(VOID) // RETURNS: VOID
{
printf(
"\nUSAGE: ACLEDIT /Profile=<ProfileName> <Folder> <Command>\n\n"
"<Folder> ::= /Store=<NameOfStore> /Folder=<FolderPath> ||\n"
" /Inbox\n\n"
"<Command> ::= /List [/Position=<Pos>] ||\n"
" /Insert /Rights=<RightLst> /User=<UserName> [/Position=<Pos>] ||\n"
" /Modify /Position=<Pos> /Rights=<RightLst> ||\n"
" /Delete /Position=<Pos> ||\n"
"<Position> ::= <ACL Number> ||\n"
" END\n\n"
"<RightLst> ::= <Right>...\n"
"<Right> ::= ReadAny ||\n"
" Create ||\n"
" EditOwned ||\n"
" DeleteOwned ||\n"
" EditAny ||\n"
" DeleteAny ||\n"
" CreateSubfolder ||\n"
" Owner ||\n"
" Contact ||\n"
" None ||\n"
" ReadOnly ||\n"
" ReadWrite ||\n"
" All ||\n"
"<UserName> ::= Display name of user against which ACL should be applied\n"
);
}
//$--EventLogHexErrorMsg-------------------------------------------------------
//
// DESCRIPTION: Write a message to the event log that contains a hex error code.
//This function is used for simple error messages that have the
//HRESULT (or other 4 byte error code) as the only insert.
//
// INPUT:
//
//[dwEvent]-- Event code for message string.
//[hr]-- HRESULT that will be printed in hex as the insert in the
// message string.
//
// RETURNS: Nothing.
//-----------------------------------------------------------------------------
VOID
EventLogHexErrorMsg(
INDWORDdwEvent,// event code for message string
INHRESULThr// HRESULT insert in the message string
)
{
CHARszErrorCode[11];
sprintf(szErrorCode, "%#.8x", hr);
EventLogMsg(dwEvent, 1, szErrorCode, 0);
}
//$--PrintErr------------------------------------------------------------------
//
// DESCRIPTION:Print an error message to stdout in a standard format.
//
// INPUT:
//
//[Format]-- Printf-style format string.
//[...]-- Variable argument parameters for format string.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
VOID
PrintErr( // RETURNS: VOID
INCHAR *Format // error message format
...
)
{
va_listargs;
DEBUGPRIVATE("PrintErr()\n");
cErrs++;
printf("ERROR: ");
va_start(args, Format);
vprintf(Format, args);
va_end(args);
printf(".\n\n");
return;
}
// $--PrintRightsString--------------------------------------------------------
//
// DESCRIPTION:Print a readable representation of the rights.
//
// INPUT:
//
//[lRights]-- Rights to be printed.
//
// RETURNS: Nothing.
//
//-----------------------------------------------------------------------------
VOID
PrintRightsString(
INLONGlRights
)
{
BOOLbSpaceNeeded =FALSE;
ULONGi =0;
// We must plow through the special cases and then hit everything
// else. We express 'ReadWrite' as 'ReadAny EditAny' since they are
// equivalent, and 'ReadOnly' as 'ReadAny' since they are equivalent.
if (lRights == rightsAll)
{
printf("All");
}
else if (lRights == rightsNone)
{
printf("None");
}
else
{
for (i = 0; i < NONEINDX; i++)
{
if (lRights & ria[i].lRights)
{
if (bSpaceNeeded)
printf(" %s", ria[i].pszKeyWord);
else
printf("%s", ria[i].pszKeyWord);
bSpaceNeeded = TRUE;
}
}
}
}
// $--Usage--------------------------------------------------------------------
//
// DESCRIPTION:Print a usage message to the console.
//
// INPUT:None.
//
// RETURNS:VOID
//-----------------------------------------------------------------------------
VOID
Usage(VOID) // RETURNS: VOID
{
DEBUGPRIVATE("Usage()\n");
printf(
"\nUSAGE: ACLEDIT /Profile=<ProfileName> <Folder> <Command>\n\n"
"Enter ACLEDIT /? for details.\n"
);
}
// $--main---------------------------------------------------------------------
//
// DESCRIPTION: acledit.exe main() routine.
//
// INPUT: Standard argc and argv.
//
// RETURNS: NOERROR on success;
// E_INVALIDARG if bad input,
// E_OUTOFMEMORY if memory problems.
// E_FAIL on any execution error.
//
//-----------------------------------------------------------------------------
HRESULT
main( // RETURNS: HRESULT
IN INT argc, // argument count
IN CHAR * argv[] // array of command line arguments
)
{
HRESULThr =NOERROR;
BOOLbMAPIInitialized =FALSE;
BOOLbPrintCompletion =TRUE;
BOOLbEventLoggingEnabled =FALSE;
DEBUGPUBLIC("main()\n");
// Initialize event logging.
hr = HrEventOpenLog("EDKAclEdit", NULL, NULL, NULL, NULL, NULL);
if (FAILED(hr))
{
PrintErr("Event logging could not be enabled; error code=%#x\n",hr);
goto cleanup;
}
else
{
bEventLoggingEnabled = TRUE;
}
// NOTE: Must initialize MAPI before parsing command line,
// as the parsing of the command line requires MAPI memory
// allocation.
if (argc == 1)
{
Usage();
bPrintCompletion = FALSE;
goto cleanup;
}
hr = MAPIInitialize(0);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_MAPIINITIALIZE_FAILED, hr);
goto cleanup;
}
bMAPIInitialized = TRUE;
if (!bParseCmdLine(argc, argv))
{
printf(" Enter ACLEDIT /? for help.\n");
hr = HR_LOG(E_INVALIDARG);
goto cleanup;
}
if (EditCmd == EDITCMD_HELP)
{
DoHelp();
hr = NOERROR;
bPrintCompletion = FALSE;
goto cleanup;
}
hr = MAPILogonEx(0,
pszProfile,
NULL,
MAPI_EXTENDED | MAPI_NEW_SESSION,
&lpSession);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_MAPILOGON_FAILED, hr);
goto cleanup;
}
// Get the entry id of the specified store and open it.
if (fInboxArgFnd)
{
hr = HrMAPIFindDefaultMsgStore(lpSession, &cbEIDStore, &lpEIDStore);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_FINDDEFAULTMSGSTORE_FAILED, hr);
goto cleanup;
}
pszFolder = "Top of Information Store\\Inbox";
}
else
{
hr = HrMAPIFindStore(lpSession, pszStore, &cbEIDStore, &lpEIDStore);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_FINDSTORE_FAILED, hr);
goto cleanup;
}
}
hr = lpSession->OpenMsgStore(0,
cbEIDStore,
lpEIDStore,
NULL,
MAPI_BEST_ACCESS|
MAPI_DEFERRED_ERRORS,
&lpStore);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_OPENMSGSTORE_FAILED, hr);
goto cleanup;
}
// Get the entry id of the specified folder and open it.
if (fInboxArgFnd)
{
LPSTRlpszExplicitClass = "";
hr = lpStore->GetReceiveFolder(NULL,
0,
&cbEIDFolder,
&lpEIDFolder,
&lpszExplicitClass);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_GETRECEIVEFOLDER_FAILED, hr);
goto cleanup;
}
pszFolder = "Inbox";
}
else
{
hr = HrMAPIFindFolderEx(lpStore,
TEXT('\\'),
pszFolder,
&cbEIDFolder,
&lpEIDFolder);
if (FAILED(hr))
{
EventLogHexErrorMsg(ACLEDIT_FINDFOLDER_FAILED, hr);
goto cleanup;
}
}
// Get a folder ACL interface ptr for the specified folder.
hr = HrFolderACLsOpen(lpSession, lpStore, cbEIDFolder, lpEIDFolder, &lpFolderACLs);
if (FAILED(hr))
{
if (hr == E_NOINTERFACE)
EventLogMsg(ACLEDIT_NOACLTABLE, 0, 0);
else
EventLogHexErrorMsg(ACLEDIT_FOLDERACLSOPEN_FAILED, hr);
goto cleanup;
}
switch (EditCmd)
{
case EDITCMD_LIST:
if (!bDoList())
{
hr = E_FAIL;
goto cleanup;
}
break;
case EDITCMD_INSERT:
if (!bDoInsert())
{
hr = E_FAIL;
goto cleanup;
}
break;
case EDITCMD_MODIFY:
if (!bDoModify())
{
hr = E_FAIL;
goto cleanup;
}
break;
case EDITCMD_DELETE:
if (!bDoDelete())
{
hr = E_FAIL;
goto cleanup;
}
break;
}
cleanup:
MAPIFREEBUFFER(lpEIDFolder);
MAPIFREEBUFFER(lpEIDStore);
ULRELEASE(lpFolderACLs);
ULRELEASE(lpStore);
if (lpSession)
{
lpSession->Logoff(0, 0, 0);
ULRELEASE(lpSession);
}
if (bMAPIInitialized)
(VOID)MAPIUninitialize();
if (bPrintCompletion)
{
EDKEVENTCOUNTEvents = {0,0,0};
HrEventGetCounts(&Events);
cErrs += Events.cError;
if (cErrs == 0)
{
printf("Execution completed with no errors.\n");
}
else
{
if (cErrs == 1)
{
printf("1 error encountered during execution.\n");
}
else
{
printf("%u errors encountered during execution.\n", cErrs);
}
if (Events.cError == 1)
{
printf("1 error written to NT Event Log.\n");
}
else if (Events.cError > 1)
{
printf("%u errors written to NT Event Log.\n", Events.cError);
}
}
}
if (bEventLoggingEnabled)
HrEventCloseLog();
return _nEcFromHr(hr);
}