|
|
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation.
//
// SYNOPSIS
//
// Declares various utility classes, functions, and macros that are useful
// when implementating a request handler for the Internet Authentication
// Service.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef IASTLUTL_H
#define IASTLUTL_H
#pragma once
//////////
// 'C'-style API for manipulating IASATTRIBUTE struct's.
//////////
#include <iasattr.h>
//////////
// 'C'-style API for manipulating dictionary.
//////////
#include <iasapi.h>
//////////
// MIDL generated header files containing interfaces used by request handlers.
//////////
#include <iaspolcy.h>
#include <sdoias.h>
//////////
// The entire library is contained within the IASTL namespace.
//////////
namespace IASTL {
//////////
// This function is called whenever an exception should be thrown. The
// function is declared, but never defined. This allows the user to provide
// their own implementation using an exception class of their choice.
//////////
void __stdcall issue_error(HRESULT hr);
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASAttribute
//
// DESCRIPTION
//
// Wrapper around an IASATTRIBUTE struct.
//
///////////////////////////////////////////////////////////////////////////////
class IASAttribute { public:
//////////
// Constructors.
//////////
IASAttribute() throw () : p(NULL) { }
explicit IASAttribute(bool alloc) { if (alloc) { _alloc(); } else { p = NULL; } }
explicit IASAttribute(PIASATTRIBUTE attr, bool addRef = true) throw () : p(attr) { if (addRef) { _addref(); } }
IASAttribute(const IASAttribute& attr) throw () : p(attr.p) { _addref(); }
//////////
// Destructor.
//////////
~IASAttribute() throw () { _release(); }
//////////
// Assignment operators.
//////////
IASAttribute& operator=(PIASATTRIBUTE attr) throw ();
const IASAttribute& operator=(const IASAttribute& attr) throw () { return operator=(attr.p); }
// Allocate a new attribute. Any existing attribute is first released.
void alloc() { _release(); _alloc(); }
// Release the attribute (if any).
void release() throw () { if (p) { IASAttributeRelease(p); p = NULL; } }
// Attach a new attribute to the object. Any existing attribute is first
// released.
void attach(PIASATTRIBUTE attr, bool addRef = true) throw ();
// Detach the attribute from the object. The caller is responsible for
// releasing the returned attribute.
PIASATTRIBUTE detach() throw () { PIASATTRIBUTE rv = p; p = NULL; return rv; }
// Load an attribute with the given ID. Returns true if successful, false
// if no such attribute exists.
bool load(IAttributesRaw* request, DWORD dwId);
// Load an attribute with the given ID and verify that it has an
// appropriate value type. Returns true if successful, false if no such
// attribute exists.
bool load(IAttributesRaw* request, DWORD dwId, IASTYPE itType);
// Store the attribute in a request.
void store(IAttributesRaw* request) const;
// Swap the contents of two objects.
void swap(IASAttribute& attr) throw () { PIASATTRIBUTE tmp = p; p = attr.p; attr.p = tmp; }
//////////
// Methods for setting the value of an attribute. The object must contain
// a valid attribute before calling this method. The passed in data is
// copied.
//////////
void setOctetString(DWORD dwLength, const BYTE* lpValue); void setOctetString(PCSTR szAnsi); void setOctetString(PCWSTR szWide);
void setString(DWORD dwLength, const BYTE* lpValue); void setString(PCSTR szAnsi); void setString(PCWSTR szWide);
//////////
// Methods for manipulating the dwFlags field.
//////////
void clearFlag(DWORD flag) throw () { p->dwFlags &= ~flag; }
void setFlag(DWORD flag) throw () { p->dwFlags |= flag; }
bool testFlag(DWORD flag) const throw () { return (p->dwFlags & flag) != 0; }
// Address-of operator. Any existing attribute is first released.
PIASATTRIBUTE* operator&() throw () { release(); return &p; }
//////////
// Assorted useful operators that allow an IASAttribute object to mimic
// an IASATTRIBUTE pointer.
//////////
bool operator !() const throw () { return p == NULL; } operator bool() const throw () { return p != NULL; } operator PIASATTRIBUTE() const throw () { return p; } IASATTRIBUTE& operator*() const throw () { return *p; } PIASATTRIBUTE operator->() const throw () { return p; }
protected: void _addref() throw () { if (p) { IASAttributeAddRef(p); } }
void _release() throw () { if (p) { IASAttributeRelease(p); } }
void _alloc() { if (IASAttributeAlloc(1, &p)) { issue_error(E_OUTOFMEMORY); } }
void clearValue() throw ();
PIASATTRIBUTE p; // The attribute being wrapped.
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASAttributePosition
//
// DESCRIPTION
//
// Wrapper around an ATTRIBUTEPOSITION struct.
//
///////////////////////////////////////////////////////////////////////////////
class IASAttributePosition { public: IASAttributePosition() throw () { pos.pAttribute = 0; }
explicit IASAttributePosition(const ATTRIBUTEPOSITION& orig) throw () : pos(orig) { _addref(); }
IASAttributePosition(const IASAttributePosition& orig) throw () : pos(orig.pos) { _addref(); }
~IASAttributePosition() throw () { _release(); }
IASAttributePosition& operator=(const ATTRIBUTEPOSITION& rhs) throw ();
IASAttributePosition& operator=(const IASAttributePosition& rhs) throw () { return operator=(rhs.pos); }
IASAttributePosition& operator=(IASATTRIBUTE* rhs) throw ();
IASATTRIBUTE* getAttribute() const throw () { return pos.pAttribute; }
ATTRIBUTEPOSITION* operator&() throw () { return &pos; }
const ATTRIBUTEPOSITION* operator&() const throw () { return &pos; }
private: void _addref() throw () { if (pos.pAttribute) { IASAttributeAddRef(pos.pAttribute); } }
void _release() throw () { if (pos.pAttribute) { IASAttributeRelease(pos.pAttribute); } }
ATTRIBUTEPOSITION pos; };
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASAttributeVector
//
// DESCRIPTION
//
// Implements an STL-style vector of ATTRIBUTEPOSITION structs. The user
// may provide an empty C-style array that will be used for initial storage.
// This array will not be freed by the IASAttributeVector object and must
// remain valid for the lifetime of the object. The purpose of this feature
// is to allow an initial stack-based allocation that will meet most
// conditions while still allowing a dynamically-sized heap-based array
// when necessary.
//
///////////////////////////////////////////////////////////////////////////////
class IASAttributeVector { public:
//////////
// STL typedefs.
//////////
typedef DWORD size_type; typedef ptrdiff_t difference_type; typedef ATTRIBUTEPOSITION& reference; typedef const ATTRIBUTEPOSITION& const_reference; typedef ATTRIBUTEPOSITION value_type; typedef PATTRIBUTEPOSITION iterator; typedef const ATTRIBUTEPOSITION* const_iterator;
// Construct a vector with zero capacity.
IASAttributeVector() throw ();
// Construct a vector with heap-allocated capacity of 'N'.
explicit IASAttributeVector(size_type N);
// Construct a vector with initial capacity of 'initCap' using the
// user-provided C-style array beginning at 'init'.
IASAttributeVector(PATTRIBUTEPOSITION init, size_type initCap) throw ();
// Copy-constructor.
IASAttributeVector(const IASAttributeVector& v);
// Assignment operator.
IASAttributeVector& operator=(const IASAttributeVector& v);
// Destructor.
~IASAttributeVector() throw ();
// Returns true if vector contains at least one attribute with the given ID.
bool contains(DWORD attrID) const throw ();
// Similar to 'erase' except the attribute is not released.
iterator discard(iterator p) throw ();
// Similar to 'discard' except the order of the elements following 'p' is
// not necessarily preserved.
iterator fast_discard(iterator p) throw ();
// Similar to 'erase' except the order of the elements following 'p' is
// not necessarily preserved.
iterator fast_erase(iterator p) throw () { IASAttributeRelease(p->pAttribute); return fast_discard(p); }
// Load the requested attributes into the vector.
DWORD load(IAttributesRaw* request, DWORD attrIDCount, LPDWORD attrIDs);
// Load all attributes with a given ID into the vector.
DWORD load(IAttributesRaw* request, DWORD attrID) { return load(request, 1, &attrID); }
// Load all the attributes in the request into the vector.
DWORD load(IAttributesRaw* request);
// Adds an ATTRIBUTEPOSITION struct to the end of the vetor, resizing as
// necessary. The 'addRef' flag indicates whether IASAttributeAddRef should
// be called for the embedded attribute.
void push_back(ATTRIBUTEPOSITION& p, bool addRef = true);
// Adds an attribute to the end of the vetor, resizing as necessary.
// The 'addRef' flag indicates whether IASAttributeAddRef should be
// called for the attribute.
void push_back(PIASATTRIBUTE p, bool addRef = true) { ATTRIBUTEPOSITION pos = { 0, p }; push_back(pos, addRef); }
// Remove the contents of the vector from the request.
void remove(IAttributesRaw* request);
// Store the contents of the vector in the request.
void store(IAttributesRaw* request) const;
//////////
// The remainder of the public interface follows the semantics of the
// STL vector class (q.v.).
//////////
const_reference at(size_type pos) const throw () { return *(begin_ + pos); }
reference at(size_type pos) throw () { return *(begin_ + pos); }
iterator begin() throw () { return begin_; }
const_iterator begin() const throw () { return begin_; }
size_type capacity() const throw () { return capacity_; }
void clear() throw ();
bool empty() const throw () { return begin_ == end_; }
iterator end() throw () { return end_; }
const_iterator end() const throw () { return end_; }
iterator erase(iterator p) throw () { IASAttributeRelease(p->pAttribute); return discard(p); }
reference back() throw () { return *(end_ - 1); }
const_reference back() const throw () { return *(end_ - 1); }
reference front() throw () { return *begin_; }
const_reference front() const throw () { return *begin_; }
void reserve(size_type N);
size_type size() const throw () { return (size_type)(end_ - begin_); }
const_reference operator[](size_type pos) const throw () { return at(pos); }
reference operator[](size_type pos) throw () { return at(pos); }
protected: PATTRIBUTEPOSITION begin_; // Beginning of the vector.
PATTRIBUTEPOSITION end_; // Points one past the last element.
size_type capacity_; // Capacity of the vector in elements.
bool owner; // true if the memory should be freed.
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASAttributeVectorWithBuffer<N>
//
// DESCRIPTION
//
// Extens IASAttributeVector to provide an initial non-heap allocation
// of 'N' elements. The vector will still support heap-based resizing.
//
///////////////////////////////////////////////////////////////////////////////
template <IASAttributeVector::size_type N> class IASAttributeVectorWithBuffer : public IASAttributeVector { public: IASAttributeVectorWithBuffer() : IASAttributeVector(buffer, N) { }
IASAttributeVectorWithBuffer(const IASAttributeVectorWithBuffer& vec) : IASAttributeVector(vec) { }
IASAttributeVectorWithBuffer& operator=(const IASAttributeVectorWithBuffer& vec) { IASAttributeVector::operator=(vec); return *this; }
protected: ATTRIBUTEPOSITION buffer[N]; // Initial storage.
};
///////////////////////////////////////////////////////////////////////////////
//
// MACRO
//
// IASAttributeVectorOnStack(identifier, request, extra)
//
// DESCRIPTION
//
// Uses _alloca to create an IASAttributeVector on the stack that is
// exactly the right size to hold all the attributes in 'request' plus
// 'extra' additional attributes. The 'request' pointer may be null in
// which case this will allocate space for exactly 'extra' attributes.
//
// CAVEAT
//
// This can only be used for temporary variables.
//
///////////////////////////////////////////////////////////////////////////////
// Must be included in an enclosing scope prior to IASAttributeVectorOnStack
#define USES_IAS_STACK_VECTOR() \
ULONG IAS_VECCAP;
#define IASAttributeVectorOnStack(identifier, request, extra) \
IAS_VECCAP = 0; \ if (static_cast<IAttributesRaw*>(request) != NULL) \ static_cast<IAttributesRaw*>(request)->GetAttributeCount(&IAS_VECCAP); \ IAS_VECCAP += (extra); \ IASAttributeVector identifier( \ (PATTRIBUTEPOSITION) \ _alloca(IAS_VECCAP * sizeof(ATTRIBUTEPOSITION)), \ IAS_VECCAP \ )
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASOrderByID
//
// DESCRIPTION
//
// Functor class for sorting/searching an IASAttributeVector by ID.
//
///////////////////////////////////////////////////////////////////////////////
class IASOrderByID { public: bool operator()(const ATTRIBUTEPOSITION& lhs, const ATTRIBUTEPOSITION& rhs) throw () { return lhs.pAttribute->dwId < rhs.pAttribute->dwId; } };
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASSelectByID<T>
//
// DESCRIPTION
//
// Functor class for selecting elements from an IASAttributeVector based
// on the attribute ID.
//
///////////////////////////////////////////////////////////////////////////////
template <DWORD ID> class IASSelectByID { public: bool operator()(const ATTRIBUTEPOSITION& pos) throw () { return (pos.pAttribute->dwId == ID); } };
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASSelectByFlag<T>
//
// DESCRIPTION
//
// Functor class for selecting elements from an IASAttributeVector based
// on the attribute flags.
//
///////////////////////////////////////////////////////////////////////////////
template <DWORD Flag, bool Set = true> class IASSelectByFlag { public: bool operator()(const ATTRIBUTEPOSITION& pos) throw () { return Set ? (pos.pAttribute->dwFlags & Flag) != 0 : (pos.pAttribute->dwFlags & Flag) == 0; } };
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASRequest
//
// DESCRIPTION
//
// Wrapper around a COM-based request object. Note that this is *not* a
// smart pointer class. There are several important differences:
//
// 1) An IASRequest object is guaranteed to contain a valid request;
// there is no concept of a NULL IASRequest.
// 2) The IASRequest object does not take ownership of the IRequest
// interface. In particular, it does not call AddRef or Release.
// 3) Methods are invoked directly on the IASRequest object rather than
// through the -> operator.
//
///////////////////////////////////////////////////////////////////////////////
class IASRequest { public:
explicit IASRequest(IRequest* request);
IASRequest(const IASRequest& request) throw () : req(request.req), raw(request.raw) { _addref(); }
IASRequest& operator=(const IASRequest& request) throw ();
~IASRequest() throw () { _release(); }
IASREQUEST get_Request() const { LONG val; checkError(req->get_Request(&val)); return (IASREQUEST)val; }
void put_Request(IASREQUEST newVal) { checkError(req->put_Request(newVal)); }
IASRESPONSE get_Response() const { LONG val; checkError(req->get_Response(&val)); return (IASRESPONSE)val; }
DWORD get_Reason() const { LONG val; checkError(req->get_Reason(&val)); return val; }
IASPROTOCOL get_Protocol() const { IASPROTOCOL val; checkError(req->get_Protocol(&val)); return val; }
void put_Protocol(IASPROTOCOL newVal) { checkError(req->put_Protocol(newVal)); }
IRequestSource* get_Source() const { IRequestSource* val; checkError(req->get_Source(&val)); return val; }
void put_Source(IRequestSource* newVal) { checkError(req->put_Source(newVal)); }
void SetResponse(IASRESPONSE eResponse, DWORD dwReason = S_OK) { checkError(req->SetResponse(eResponse, (LONG)dwReason)); }
void ReturnToSource(IASREQUESTSTATUS eStatus) { checkError(req->ReturnToSource(eStatus)); }
void AddAttributes(DWORD dwPosCount, PATTRIBUTEPOSITION pPositions) { checkError(raw->AddAttributes(dwPosCount, pPositions)); }
void RemoveAttributes(DWORD dwPosCount, PATTRIBUTEPOSITION pPositions) { checkError(raw->RemoveAttributes(dwPosCount, pPositions)); }
void RemoveAttributesByType(DWORD dwAttrIDCount, LPDWORD lpdwAttrIDs) { checkError(raw->RemoveAttributesByType(dwAttrIDCount, lpdwAttrIDs)); }
DWORD GetAttributeCount() const { DWORD count; checkError(raw->GetAttributeCount(&count)); return count; }
// Returns the number of attributes retrieved.
DWORD GetAttributes(DWORD dwPosCount, PATTRIBUTEPOSITION pPositions, DWORD dwAttrIDCount, LPDWORD lpdwAttrIDs);
void InsertBefore( PATTRIBUTEPOSITION newAttr, PATTRIBUTEPOSITION refAttr ) { checkError(raw->InsertBefore(newAttr, refAttr)); }
//////////
// Cast operators to extract the embedded interfaces.
//////////
operator IRequest*() { return req; } operator IAttributesRaw*() { return raw; }
protected:
// Throws an exception if a COM method fails.
static void checkError(HRESULT hr) { if (FAILED(hr)) { issue_error(hr); } }
void _addref() { raw->AddRef(); } void _release() { raw->Release(); }
IRequest* req; // Underlying interfaces.
IAttributesRaw* raw; // Underlying interfaces.
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// IASDictionary
//
// DESCRIPTION
//
// Provides access to the attribute dictionary.
//
///////////////////////////////////////////////////////////////////////////////
class IASDictionary { public: // selectNames: null terminated array of strings containing the columns to
// be selected; a column name may be prepended with a hyphen
// '-' to indicate that it's optional
// path: full path to the dictionary database or NULL to use the
// local dictionary
IASDictionary( const WCHAR* const* selectNames, PCWSTR path = NULL ); ~IASDictionary() throw ();
ULONG getNumRows() const throw () { return table->numRows; }
// Advance to the next row. This must be called on a newly constructed
// dictionary to advance to the first row.
bool next() throw ();
// Reset the dictionary to its initial state.
void reset() throw ();
// Returns true if the specified column is empty in the current row.
bool isEmpty(ULONG ordinal) const;
// Retrieve column values from the current row.
VARIANT_BOOL getBool(ULONG ordinal) const; BSTR getBSTR(ULONG ordinal) const; LONG getLong(ULONG ordinal) const; const VARIANT* getVariant(ULONG ordinal) const;
private: const IASTable* table; // The table data.
ULONG mapSize; // Number of columns selected.
PULONG selectMap; // Maps select ordinals to table ordinals.
ULONG nextRowNumber; // Next row.
VARIANT* currentRow; // Current row -- may be NULL.
IASTable data; // Local storage for non-local dictionaries.
CComVariant storage; // Storage associated with the dictionary.
// Not implemented.
IASDictionary(const IASDictionary&); IASDictionary& operator=(const IASDictionary&); };
//////////
// End of the IASTL namespace.
//////////
}
///////////////////////////////////////////////////////////////////////////////
//
// OctetString conversion macros and functions.
//
///////////////////////////////////////////////////////////////////////////////
// Compute the size of the buffer required by IASOctetStringToAnsi
#define IAS_OCT2ANSI_LEN(oct) \
(((oct).dwLength + 1) * sizeof(CHAR))
// Compute the size of the buffer required by IASOctetStringToWide
#define IAS_OCT2WIDE_LEN(oct) \
(((oct).dwLength + 1) * sizeof(WCHAR))
// Coerce an OctetString to a null-terminated ANSI string. There is no check
// for overflow. The dst buffer must be at least IAS_OCT2ANSI_LEN bytes.
PSTR IASOctetStringToAnsi(const IAS_OCTET_STRING& src, PSTR dst) throw ();
// Coerce an OctetString to a null-terminated Unicode string. There is no
// check for overflow. The dst buffer must be at least IAS_OCT2UNI_LEN bytes.
PWSTR IASOctetStringToWide(const IAS_OCTET_STRING& src, PWSTR dst) throw ();
// Convert an OctetString to ANSI on the stack.
#define IAS_OCT2ANSI(oct) \
(IASOctetStringToAnsi((oct), (PSTR)_alloca(IAS_OCT2ANSI_LEN(oct))))
// Convert an OctetString to Unicode on the stack.
#define IAS_OCT2WIDE(oct) \
(IASOctetStringToWide((oct), (PWSTR)_alloca(IAS_OCT2WIDE_LEN(oct))))
///////////////////////////////////////////////////////////////////////////////
//
// Miscellaneous utility functions.
//
///////////////////////////////////////////////////////////////////////////////
// Retrieves and returns a single attribute with the given ID and type. The
// attribute should *not* be released and is only valid while the caller holds
// a reference to 'request'. On error or if the attribute is not found, the
// function returns NULL.
PIASATTRIBUTE IASPeekAttribute( IAttributesRaw* request, DWORD dwId, IASTYPE itType ) throw ();
#endif // IASTLUTL_H
|