685 lines
15 KiB
C++
685 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
adl.h
|
|
|
|
Abstract:
|
|
|
|
The header file for the ADL language parser / printer
|
|
|
|
Author:
|
|
|
|
t-eugenz - August 2000
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
Revision History:
|
|
|
|
Created - August 2000
|
|
|
|
--*/
|
|
|
|
|
|
#include "pch.h"
|
|
#include "adlinterface.h"
|
|
|
|
#include <string>
|
|
#include <list>
|
|
#include <stack>
|
|
#include <map>
|
|
|
|
using namespace std;
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
|
|
class AdlToken;
|
|
class AdlLexer;
|
|
class AdlTree;
|
|
class AdlStatement;
|
|
|
|
|
|
struct AdlCompareStruct
|
|
/*++
|
|
|
|
Struct: AdlCompareStruct
|
|
|
|
Description:
|
|
|
|
STL requires custom key comparisons for containers to be supplied in
|
|
such a struct.
|
|
|
|
--*/
|
|
|
|
{
|
|
bool operator()(IN const PSID pSid1,
|
|
IN const PSID pSid2) const;
|
|
|
|
bool operator()(IN const WCHAR * sz1,
|
|
IN const WCHAR * sz2) const;
|
|
};
|
|
|
|
|
|
|
|
class AdlStatement
|
|
/*++
|
|
|
|
Class: AdlStatement
|
|
|
|
Description:
|
|
|
|
This class contains a description of a DACL on an object, using the ADL
|
|
language. An instance of this class can be constructed from an ACL or
|
|
from a string statement in the ADL language. Once constructed, an ACL
|
|
or a string statement in the ADL language can be output by an instance
|
|
of this class.
|
|
|
|
Base Classes: none
|
|
|
|
Friend Classes: AdlLexer
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Friend classes necessary to access the garbage collection functionality,
|
|
// and for parsing ADL
|
|
//
|
|
|
|
friend class AdlLexer;
|
|
|
|
public:
|
|
|
|
//
|
|
// Initializes the AdlStatement
|
|
//
|
|
|
|
AdlStatement(IN const PADL_PARSER_CONTROL pControl)
|
|
{ _bReady = FALSE; _tokError = NULL; _pControl = pControl;
|
|
ValidateParserControl(); }
|
|
|
|
|
|
//
|
|
// Destructor, frees tokens created by this and other classes
|
|
//
|
|
|
|
~AdlStatement();
|
|
|
|
//
|
|
// Reads in the ADL statement in the input string
|
|
//
|
|
|
|
void ReadFromString(IN const WCHAR *szInput);
|
|
|
|
//
|
|
// Creates an ADL statement equivalent to the given DACL
|
|
//
|
|
|
|
void ReadFromDacl(IN const PACL pDacl);
|
|
|
|
|
|
//
|
|
// Prints the AdlStatement as a statement in the ADL language,
|
|
// appending it to the allocated STL wstring pSz
|
|
//
|
|
|
|
void WriteToString(OUT wstring *pSz);
|
|
|
|
//
|
|
// Writes the ADL statement to a new DACL and returns the pointer to
|
|
// the new DACL in *ppDacl
|
|
//
|
|
|
|
void WriteToDacl(OUT PACL *ppDacl);
|
|
|
|
//
|
|
// Gets the error string token, if any (depends on error code)
|
|
//
|
|
|
|
const AdlToken * GetErrorToken()
|
|
{ return _tokError; }
|
|
|
|
//
|
|
// This should be used to free any memory allocated by this class
|
|
//
|
|
|
|
static void FreeMemory(PVOID pMem)
|
|
{ delete[] (PBYTE) pMem; }
|
|
|
|
|
|
|
|
public:
|
|
|
|
//
|
|
// AdlStatement throws exceptions of this type on any error
|
|
// Some of the errors will make the offending token available
|
|
// through GetErrorToken()
|
|
//
|
|
|
|
typedef enum
|
|
{
|
|
ERROR_NO_ERROR = 0,
|
|
|
|
//
|
|
// Internal errors which shoul not occur
|
|
//
|
|
|
|
ERROR_FATAL_LEXER_ERROR,
|
|
ERROR_FATAL_PARSER_ERROR,
|
|
ERROR_FATAL_ACL_CONVERT_ERROR,
|
|
|
|
|
|
//
|
|
// Errors due to the system the code is running on
|
|
//
|
|
|
|
ERROR_OUT_OF_MEMORY,
|
|
ERROR_ACL_API_FAILED,
|
|
|
|
//
|
|
// Possible error due to network problems
|
|
//
|
|
|
|
ERROR_LSA_FAILED,
|
|
|
|
|
|
//
|
|
// If the ADL_PARSER_CONTROL is invalid, this is thrown
|
|
//
|
|
|
|
ERROR_INVALID_PARSER_CONTROL,
|
|
|
|
//
|
|
// Unknown ACE type encountered in DACL, no token supplied
|
|
//
|
|
|
|
ERROR_UNKNOWN_ACE_TYPE,
|
|
|
|
//
|
|
// User tried to specify impersonation as "user1 as user2"
|
|
// Not currently supported
|
|
//
|
|
|
|
ERROR_IMPERSONATION_UNSUPPORTED,
|
|
|
|
|
|
//
|
|
// User error, no token supplied, quote with no closing quote
|
|
//
|
|
|
|
ERROR_UNTERMINATED_STRING,
|
|
|
|
//
|
|
// The user's statement was not in the ADL language (grammar error)
|
|
// For this error, the offending token is supplied, though
|
|
// the mistake may have happened before that token and was
|
|
// accepted by the grammar
|
|
//
|
|
|
|
ERROR_NOT_IN_LANGUAGE,
|
|
|
|
|
|
//
|
|
// User input-related errors
|
|
// For these errors, the offending token is supplied
|
|
//
|
|
|
|
//
|
|
// User was not found by LSA lookup
|
|
//
|
|
|
|
ERROR_UNKNOWN_USER,
|
|
|
|
//
|
|
// Permission string was not one of those listed in the parser control
|
|
//
|
|
|
|
ERROR_UNKNOWN_PERMISSION,
|
|
|
|
//
|
|
// Username contained invalid characters
|
|
//
|
|
|
|
ERROR_INVALID_USERNAME,
|
|
|
|
//
|
|
// Domain name contained invalid characters
|
|
//
|
|
|
|
ERROR_INVALID_DOMAIN,
|
|
|
|
//
|
|
// Invalid inheritance specified. Not currently used, since
|
|
// object type errors are caught at the grammar level
|
|
//
|
|
|
|
ERROR_INVALID_OBJECT,
|
|
|
|
//
|
|
// Other errors with no token supplied
|
|
//
|
|
|
|
//
|
|
// A SID in an ACE was not found and mapped to a name by the LSA lookup
|
|
//
|
|
|
|
ERROR_UNKNOWN_SID,
|
|
|
|
//
|
|
// An access mask was encountered in an ACE that could not be
|
|
// expressed by the user-specified permission mapping
|
|
//
|
|
|
|
ERROR_UNKNOWN_ACCESS_MASK,
|
|
|
|
//
|
|
// The ACL cannot be expressed in ADL. This means that, for some access
|
|
// mask bit and set of inheritance flags, there exists a DENY ACE in the
|
|
// ACL with the given bit set in its mask and with the given flags such
|
|
// that either there is no ALLOW ACE which also has this bit set and has
|
|
// the same inheritance flags further down in the ACL, or another
|
|
// ACE with DIFFERENT inheritance flags and the same bit set follows
|
|
// this DENY ace. For more information, see the ADL conversion
|
|
// algorithm.
|
|
//
|
|
ERROR_INEXPRESSIBLE_ACL,
|
|
|
|
//
|
|
// User attempted an output operation on AdlStatement without
|
|
// first successfully inputting data from either a string or an ACL
|
|
//
|
|
|
|
ERROR_NOT_INITIALIZED
|
|
|
|
} ADL_ERROR_TYPE;
|
|
|
|
private:
|
|
|
|
//
|
|
// Internal representation of an ADL statement
|
|
//
|
|
|
|
list<AdlTree *> _lTree; // A set of parsed ADL statements, as AdlTree's
|
|
|
|
list<AdlTree *>::iterator _iter; // Iterator for the above set
|
|
|
|
stack<AdlToken *> _AllocatedTokens; // Tokens to be garbage collected
|
|
|
|
PADL_PARSER_CONTROL _pControl;
|
|
|
|
const AdlToken * _tokError;
|
|
|
|
BOOL _bReady;
|
|
|
|
private:
|
|
|
|
//
|
|
// Goes through the list of AdlTrees, collects a list of all usernames
|
|
// used, and makes a single LSA call to look up all SIDs, inserting the
|
|
// PSIDs into the map by the (unique) token pointer.
|
|
//
|
|
|
|
void ConvertNamesToSids(
|
|
IN OUT map<const AdlToken *, PSID> * mapTokSid
|
|
);
|
|
|
|
//
|
|
// Goes throw the DACL, collects a lost of all SIDs used, and makes a
|
|
// single LSA call to look up all names, inserting the looked up
|
|
// names into the provided map as AdlTokens, which are garbage-
|
|
// collected when the AdlStatement is deleted
|
|
//
|
|
|
|
void ConvertSidsToNames(
|
|
IN const PACL pDacl,
|
|
IN OUT map<const PSID, const AdlToken *> * mapSidsNames
|
|
);
|
|
|
|
//
|
|
// Reads a DACL, and constructs an ADL statement from it
|
|
//
|
|
|
|
void ConvertFromDacl(
|
|
IN const PACL pDacl
|
|
);
|
|
|
|
//
|
|
// Returns the access mask corresponding to the given right name
|
|
//
|
|
|
|
ACCESS_MASK MapTokenToMask(
|
|
IN const AdlToken * tokPermission
|
|
);
|
|
|
|
//
|
|
// Fills in a list ofr const WCHAR *'s matching the passed in access
|
|
// mask, using the preference order given in the grammar
|
|
//
|
|
|
|
void MapMaskToStrings(IN ACCESS_MASK amMask,
|
|
IN OUT list<WCHAR *> *pList
|
|
) const;
|
|
|
|
//
|
|
// Cleans up all of the AdlTrees and all tokens
|
|
//
|
|
|
|
void Cleanup();
|
|
|
|
//
|
|
// Parses a string in the ADL language
|
|
// This function is generated by YACC from the ADL grammar
|
|
//
|
|
|
|
int ParseAdl(IN const WCHAR *szInput);
|
|
|
|
//
|
|
// Returns the current AdlTree, this is used by the ADL parser to create
|
|
// an ADL statement, one tree at a time
|
|
//
|
|
|
|
AdlTree * Cur();
|
|
|
|
//
|
|
// Creates a new AdlTree and pushes it onto the top of the list
|
|
// Used by the ADL parser once the end of a single ADL statement is reached
|
|
//
|
|
|
|
void Next();
|
|
|
|
|
|
//
|
|
// If the last added AdlTree is empty, remove it
|
|
// Used by the ADL parser, since it adds an AdlTree at the end
|
|
// of a production instead of the beginning (YACC problem)
|
|
//
|
|
|
|
void PopEmpty();
|
|
|
|
//
|
|
// This is used to validate passed in ADL_PARSER_CONTROL structure
|
|
// referenced by this class
|
|
//
|
|
|
|
void ValidateParserControl();
|
|
|
|
protected:
|
|
|
|
//
|
|
// Used to set the error-causing string
|
|
//
|
|
|
|
void SetErrorToken(const AdlToken *tokError)
|
|
{ _tokError = tokError; }
|
|
|
|
//
|
|
// Adds a token pointer to be deleted when the AdlStatement is deleted
|
|
//
|
|
|
|
void AddToken(IN AdlToken *tok);
|
|
};
|
|
|
|
|
|
|
|
|
|
class AdlLexer
|
|
/*++
|
|
|
|
Class: AdlLexer
|
|
|
|
Description:
|
|
|
|
This class is the lexer for the ADL language. It allows the ADL parser
|
|
to retrieve tokens from an input string, one token at a time.
|
|
|
|
Base Classes: none
|
|
|
|
Friend Classes: none
|
|
|
|
--*/
|
|
{
|
|
|
|
private:
|
|
|
|
const WCHAR *_input; // The input string
|
|
|
|
DWORD _position; // Current position in the input string
|
|
|
|
DWORD _start; // Start of current token in the buffer
|
|
|
|
DWORD _tokCount; // Number of tokens so far retrieved
|
|
|
|
//
|
|
// Pointer to the AdlStatement instance which created this AdlLexer
|
|
// instance, for token garbage collection
|
|
//
|
|
|
|
AdlStatement *_adlStat;
|
|
|
|
//
|
|
// Pointer to the ADL_LANGUAGE_SPEC structure defining the language to
|
|
// be parsed
|
|
//
|
|
|
|
PADL_LANGUAGE_SPEC _pLang;
|
|
|
|
//
|
|
// Mapping of special characters to character codes
|
|
// Special characters are assigned codes above WCHAR max
|
|
//
|
|
|
|
map<WCHAR, DWORD> _mapCharCode;
|
|
|
|
//
|
|
// Mapping from wstring to identify special tokens
|
|
//
|
|
|
|
map<const WCHAR *, DWORD, AdlCompareStruct> _mapStringToken;
|
|
|
|
//
|
|
// Iterators used by NextToken, this way they are only allocated once
|
|
//
|
|
|
|
map<WCHAR, DWORD>::iterator _iterEnd;
|
|
map<WCHAR, DWORD>::iterator _iter;
|
|
|
|
|
|
public:
|
|
|
|
//
|
|
// Constructs a lexer for an input string
|
|
// NextToken() can then be called
|
|
//
|
|
|
|
AdlLexer(IN const WCHAR *input,
|
|
IN OUT AdlStatement *adlStat,
|
|
IN const PADL_LANGUAGE_SPEC pLang);
|
|
|
|
//
|
|
// Retrieves the next token from the input string
|
|
// Returns 0 for the token type when the end of the string
|
|
// is reached, as the YACC-generated parser requires.
|
|
// A pointer to a new token instance containing the token
|
|
// string, row, col, etc, is stored in *value
|
|
//
|
|
|
|
DWORD NextToken(OUT AdlToken **value);
|
|
};
|
|
|
|
|
|
|
|
class AdlToken
|
|
/*++
|
|
|
|
Class: AdlToken
|
|
|
|
Description:
|
|
|
|
This class contains the relevant information for a token. It is used in
|
|
parsing ADL.
|
|
|
|
Base Classes: none
|
|
|
|
Friend Classes: none
|
|
|
|
--*/
|
|
{
|
|
private:
|
|
|
|
DWORD _begin; // Start position in the buffer
|
|
|
|
DWORD _end; // End position in the buffer
|
|
|
|
wstring _value; // String value of token
|
|
|
|
//
|
|
// This allows for collapsing multi-part tokens
|
|
// such as user@domain.domain.domain into a single
|
|
// token by the parser after the individual subparts
|
|
// are verified
|
|
//
|
|
|
|
wstring _optValue;
|
|
|
|
public:
|
|
|
|
//
|
|
// Constructor for a single-part token
|
|
//
|
|
|
|
AdlToken(IN const WCHAR *value,
|
|
IN DWORD begin,
|
|
IN DWORD end
|
|
)
|
|
{ _value.append(value); _begin = begin; _end = end; }
|
|
|
|
//
|
|
// Constructor for a multi-part token
|
|
//
|
|
|
|
AdlToken(IN const WCHAR *value,
|
|
IN const WCHAR *optValue,
|
|
IN DWORD begin,
|
|
IN DWORD end
|
|
)
|
|
{ _value.append(value); _optValue.append(optValue);
|
|
_begin = begin; _end = end; }
|
|
|
|
|
|
//
|
|
// Accessors
|
|
//
|
|
|
|
DWORD GetStart() const
|
|
{ return _begin; }
|
|
|
|
DWORD GetEnd() const
|
|
{ return _end; }
|
|
|
|
const WCHAR * GetValue() const
|
|
{ return _value.c_str(); }
|
|
|
|
const WCHAR * GetOptValue() const
|
|
{ return (_optValue.empty() ? NULL : _optValue.c_str()); }
|
|
};
|
|
|
|
|
|
|
|
|
|
class AdlTree
|
|
/*++
|
|
|
|
Class: AdlTree
|
|
|
|
Description:
|
|
|
|
This class contains the parsed information from a single ADL
|
|
substatement, still in string form. The inheritance information
|
|
is converted to a mask. The names contained are not necessarily
|
|
valid however.
|
|
|
|
Base Classes: none
|
|
|
|
Friend Classes: none
|
|
|
|
--*/
|
|
{
|
|
private:
|
|
|
|
list<const AdlToken *> _lpTokPrincipals;
|
|
list<const AdlToken *> _lpTokExPrincipals;
|
|
list<const AdlToken *> _lpTokPermissions;
|
|
|
|
DWORD _dwInheritFlags;
|
|
|
|
public:
|
|
|
|
//
|
|
// Default to inherit-only, since "this object" must be specified
|
|
// to clear that bit
|
|
//
|
|
|
|
AdlTree()
|
|
{ _dwInheritFlags = INHERIT_ONLY_ACE; }
|
|
//
|
|
// This outputs the ADL statement to stdout
|
|
// Later to go to a string
|
|
//
|
|
|
|
void PrintAdl(wstring *pSz, PADL_PARSER_CONTROL pControl);
|
|
|
|
//
|
|
// Accessors/mutators
|
|
// The Add*/Set* mutators are used by the YACC-generated AdlParse()
|
|
// function to store information as it is parsed, adding the tokens
|
|
// to the correct places in the AdlTree
|
|
//
|
|
|
|
void AddPrincipal(IN const AdlToken * pTokPrincipal)
|
|
{ _lpTokPrincipals.push_back(pTokPrincipal); }
|
|
|
|
void AddExPrincipal(IN const AdlToken * pTokPrincipal)
|
|
{ _lpTokExPrincipals.push_back(pTokPrincipal); }
|
|
|
|
void AddPermission(IN const AdlToken * pTokPermission)
|
|
{ _lpTokPermissions.push_back(pTokPermission); }
|
|
|
|
//
|
|
// Accessors used by AdlStat conversion functions
|
|
//
|
|
|
|
list<const AdlToken *> * GetPrincipals()
|
|
{ return &_lpTokPrincipals; }
|
|
|
|
list<const AdlToken *> * GetExPrincipals()
|
|
{ return &_lpTokExPrincipals; }
|
|
|
|
list<const AdlToken *> * GetPermissions()
|
|
{ return &_lpTokPermissions; }
|
|
|
|
//
|
|
// Set/unset/get inheritance flags
|
|
//
|
|
|
|
void SetFlags(DWORD dwFlags)
|
|
{ _dwInheritFlags |= dwFlags; }
|
|
|
|
void UnsetFlags(DWORD dwFlags)
|
|
{ _dwInheritFlags &= (~dwFlags); }
|
|
|
|
void OverwriteFlags(DWORD dwFlags)
|
|
{ _dwInheritFlags = dwFlags; }
|
|
|
|
DWORD GetFlags()
|
|
{ return _dwInheritFlags; }
|
|
|
|
};
|
|
|
|
|
|
|