You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
7.1 KiB
285 lines
7.1 KiB
/*
|
|
* S A F E O B J . H
|
|
*
|
|
* Implementation of safe object classes
|
|
*
|
|
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
*/
|
|
|
|
#ifndef _SAFEOBJ_H_
|
|
#define _SAFEOBJ_H_
|
|
|
|
#include <except.h>
|
|
|
|
// safe_xxx classes ----------------------------------------------------------
|
|
//
|
|
class safe_bstr
|
|
{
|
|
BSTR bstr;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
safe_bstr(const safe_bstr& b);
|
|
safe_bstr& operator=(const safe_bstr& b);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit safe_bstr(BSTR b=0) : bstr(b) {}
|
|
~safe_bstr()
|
|
{
|
|
SysFreeString (bstr);
|
|
}
|
|
|
|
// MANIPULATORS
|
|
//
|
|
safe_bstr& operator=(BSTR b)
|
|
{
|
|
Assert(!bstr); // Scream on overwrite of good data.
|
|
bstr = b;
|
|
return *this;
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
BSTR* operator&() { Assert(NULL==bstr); return &bstr; }
|
|
BSTR get() const { return bstr; }
|
|
BSTR relinquish() { BSTR b = bstr; bstr = 0; return b; }
|
|
BSTR* load() { Assert(NULL==bstr); return &bstr; }
|
|
};
|
|
|
|
class safe_propvariant
|
|
{
|
|
PROPVARIANT var;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
safe_propvariant(const safe_propvariant& b);
|
|
safe_propvariant& operator=(const safe_propvariant& b);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit safe_propvariant()
|
|
{
|
|
// Note! we cannot simply set vt to VT_EMPTY, as when this
|
|
// structure go across process, it will cause marshalling
|
|
// problem if not property initialized.
|
|
//
|
|
ZeroMemory (&var, sizeof(PROPVARIANT) );
|
|
}
|
|
|
|
~safe_propvariant()
|
|
{
|
|
PropVariantClear (&var);
|
|
}
|
|
|
|
// MANIPULATORS
|
|
//
|
|
safe_propvariant& operator=(PROPVARIANT v)
|
|
{
|
|
Assert(var.vt == VT_EMPTY); // Scream on overwrite of good data.
|
|
var = v;
|
|
return *this;
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
PROPVARIANT* operator&() { Assert(var.vt == VT_EMPTY); return &var; }
|
|
// get() accessor
|
|
// NOTE that I am returning a const reference here. The reference is to
|
|
// avoid creating a copy of our member var on return. The const is
|
|
// because this method is a const accessor method.
|
|
const PROPVARIANT& get() const { return var; }
|
|
// relinquish() accessor
|
|
// NOTE that I am NOT returning a reference here. The return for this
|
|
// method comes off the STACK (PROPVARIANT v), so a reference would point
|
|
// to that stack space, and our caller would be accessing OLD STACK frames.
|
|
PROPVARIANT relinquish() { PROPVARIANT v = var; var.vt = VT_EMPTY; return v; }
|
|
PROPVARIANT* addressof() { return &var; }
|
|
};
|
|
|
|
class safe_variant
|
|
{
|
|
// IMPORTANT: Do not add any other members to this class
|
|
// other than the VARIANT that is to be protected. You will
|
|
// break code all over the place if you do. There are places
|
|
// where an array of these things are treated as an array of
|
|
// VARIANT structures.
|
|
//
|
|
VARIANT var;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
safe_variant(const safe_variant& b);
|
|
safe_variant& operator=(const safe_variant& b);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit safe_variant()
|
|
{
|
|
// Note! we cannot simply set vt to VT_EMPTY, as when this
|
|
// structure go across process, it will cause marshalling
|
|
// problem if not property initialized.
|
|
//
|
|
ZeroMemory (&var, sizeof(VARIANT) );
|
|
}
|
|
~safe_variant()
|
|
{
|
|
VariantClear (&var);
|
|
}
|
|
|
|
// MANIPULATORS
|
|
//
|
|
safe_variant& operator=(VARIANT v)
|
|
{
|
|
Assert(var.vt == VT_EMPTY); // Scream on overwrite of good data.
|
|
var = v;
|
|
return *this;
|
|
}
|
|
|
|
// ACCESSORS
|
|
//
|
|
VARIANT* operator&() { Assert(var.vt == VT_EMPTY); return &var; }
|
|
// get() accessor
|
|
// NOTE that I am returning a const reference here. The reference is to
|
|
// avoid creating a copy of our member var on return. The const is
|
|
// because this method is a const accessor method.
|
|
const VARIANT& get() const { return var; }
|
|
// relinquish() accessor
|
|
// NOTE that I am NOT returning a reference here. The return for this
|
|
// method comes off the STACK (PROPVARIANT v), so a reference would point
|
|
// to that stack space, and our caller would be accessing OLD STACK frames.
|
|
VARIANT relinquish() { VARIANT v = var; var.vt = VT_EMPTY; return v; }
|
|
};
|
|
|
|
// Safe impersonation --------------------------------------------------------
|
|
//
|
|
class safe_impersonation
|
|
{
|
|
BOOL m_fImpersonated;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
safe_impersonation(const safe_impersonation& b);
|
|
safe_impersonation& operator=(const safe_impersonation& b);
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
|
//
|
|
explicit safe_impersonation(HANDLE h = 0) : m_fImpersonated(0)
|
|
{
|
|
if (h != 0)
|
|
m_fImpersonated = ImpersonateLoggedOnUser (h);
|
|
}
|
|
|
|
~safe_impersonation()
|
|
{
|
|
if (m_fImpersonated)
|
|
RevertToSelf();
|
|
}
|
|
|
|
BOOL FImpersonated() const { return m_fImpersonated; }
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// class safe_revert
|
|
//
|
|
// Turns impersonation OFF for the duration of the object's lifespan.
|
|
// Unconditionally reimpersonates on exit, based on the provided handle.
|
|
//
|
|
// NOTE: UNCONDITIONALLY reimpersonates on exit.
|
|
// (Just wanted to make that clear.)
|
|
//
|
|
// WARNING: the safe_revert class should only be used in very selective
|
|
// situations. It is not a "quick way to get around" impersonation. If
|
|
// you do need to do something like this, please see Becky -- she will then
|
|
// wack you up'side the head.
|
|
//
|
|
class safe_revert
|
|
{
|
|
HANDLE m_h;
|
|
|
|
safe_revert( const safe_revert& );
|
|
safe_revert& operator=( const safe_revert& );
|
|
|
|
public:
|
|
|
|
explicit safe_revert( HANDLE h ) : m_h(h)
|
|
{
|
|
RevertToSelf();
|
|
}
|
|
|
|
~safe_revert()
|
|
{
|
|
if (!ImpersonateLoggedOnUser( m_h ))
|
|
{
|
|
// There's not much we can do in this dtor. throw
|
|
//
|
|
throw CLastErrorException();
|
|
}
|
|
}
|
|
};
|
|
|
|
// -------------------------------------------------------------------------
|
|
//
|
|
// class safe_revert_self
|
|
//
|
|
// This is class is essentially the same as safe_revert except it uses
|
|
// the thread handle instead of an external handle
|
|
//
|
|
class safe_revert_self
|
|
{
|
|
// Handle to hold on to the thread token
|
|
// that we will want to use when we go back
|
|
// to impersonating.
|
|
//
|
|
HANDLE m_hThreadHandle;
|
|
|
|
public:
|
|
|
|
// constructor will revert to self if there is
|
|
// a valid thread token it can get for the current thread
|
|
//
|
|
safe_revert_self() :
|
|
m_hThreadHandle (INVALID_HANDLE_VALUE)
|
|
{
|
|
if (OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
|
|
TRUE, // fOpenAsSelf
|
|
&m_hThreadHandle ))
|
|
{
|
|
if (!RevertToSelf())
|
|
DebugTrace ("Failed to revert to self \r\n");
|
|
}
|
|
else
|
|
DebugTrace ("Failed to open thread token, last error = %d\n",
|
|
GetLastError());
|
|
}
|
|
|
|
// destructor will impersonate again if we did a RevertToSelf above.
|
|
//
|
|
~safe_revert_self()
|
|
{
|
|
if (m_hThreadHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!ImpersonateLoggedOnUser(m_hThreadHandle))
|
|
{
|
|
DebugTrace("Failed to get back to correct user \r\n");
|
|
|
|
// There's not much we can do in this dtor. throw
|
|
//
|
|
CloseHandle (m_hThreadHandle);
|
|
throw CLastErrorException();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif // _SAFEOBJ_H_
|