Leaked source code of windows server 2003
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

/*
* 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_