Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55590)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55591)
@@ -5158,4 +5158,9 @@
         <link to="IConsole::powerUp"/>.
 
+<!-- TODO/r=bird: What about making @a environment into a smart array?  Guess
+this predates our safe array support by a year or so... Dmitry wrote the text here, right?
+Just rename it to @a environmentChanges and shorten the documentation to say the string
+are applied onto the server environment putenv style, i.e. "VAR=VALUE" for setting/replacing
+and "VAR" for unsetting. -->
         The @a environment argument is a string containing definitions of
         environment variables in the following format:
@@ -10242,5 +10247,11 @@
     </const>
     <const name="ExpandArguments"           value="64">
-      <desc>Expands environment variables in process arguments.</desc>
+      <desc>Expands environment variables in process arguments.
+        <note>
+          This is not yet implemented and is currently silently ignored.
+          We will document the protocolVersion number for this feature once it
+          appears, so don't use it till then.
+        </note>
+      </desc>
     </const>
     <const name="UnquotedArguments"         value="128">
@@ -10783,5 +10794,5 @@
   <interface
     name="IGuestSession" extends="$unknown"
-    uuid="e1fa83fe-437d-3e3a-9278-4297f1ca95dd"
+    uuid="bb890975-4903-38f8-4bc2-f39341f95533"
     wsmap="managed"
     >
@@ -10795,20 +10806,36 @@
 <!-- r=bird: Is the root session part of the maximum of 32?? Not really clear. -->
       This root session is controlling all other guest sessions and also is
-      responsible for actions which require system level privileges.  Each
-      guest session keeps track of its started guest processes, opened guest
-      files or guest directories.  To work on guest files or directories a
-      guest session offers methods to open or create such objects (see
-      <link to="IGuestSession::fileOpen"/> or
-      <link to="IGuestSession::directoryOpen"/> for example).
+      responsible for actions which require system level privileges.
+
+      Each guest session keeps track of the guest directories and files that
+      it opened as well as guest processes it has created.  To work on guest
+      files or directories a guest session offers methods to open or create
+      such objects (see <link to="IGuestSession::fileOpen"/> or
+      <link to="IGuestSession::directoryOpen"/> for instance).  Similarly,
+      there a methods for creating guest processes.
+
+      There can be up to 2048 objects (guest processes, files and directories)
+      a time per guest session.  Exceeding the limit will result in an error.
+<!-- @todo r=bird: Add specific VBOX_E_XXX error for this and document it here! -->
 
       When done with either of these objects, including the guest session itself,
       use the appropriate close() method to let the object do its cleanup work.
 
-      A set of environment variables changes is associated with each session.
-      These are applied to the standard environment of the impersonated guest
-      user when creating a new guest process.  For additional flexibility the
-      <link to="IGuestSession::processCreate"/> and
-      <link to="IGuestSession::processCreateEx"/> methods allows you to specify
-      individual environment changes for each process you create.
+      Closing a session via <link to="IGuestSession::close" /> will try to close
+      all the mentioned objects above unless these objects are still used by
+      a client.
+
+      A set of environment variables changes is associated with each session
+      (<link to="IGuestSession::environmentChanges"/>).  These are applied to
+      the base environment of the impersonated guest user when creating a new
+      guest process.  For additional flexibility the <link to="IGuestSession::processCreate"/>
+      and <link to="IGuestSession::processCreateEx"/> methods allows you to
+      specify individual environment changes for each process you create.
+      With newer guest addition versions, the base environment is also made
+      available via <link to="IGuestSession::environmentBase"/>.  (One reason
+      for why we record changes to a base environment instead of working
+      directly on an environment block is that we need to be compatible
+      with older guest additions.  Another reason is that this way it is always
+      possible to undo all the changes you've scheduled.)
     </desc>
 
@@ -10845,12 +10872,32 @@
       <desc>Returns the current session status.</desc>
     </attribute>
-    <attribute name="environment" type="wstring" safearray="yes">
-      <!-- r=bird: Would probably be a great idea to rename this attribute as
-                   it is misleading and will cause worse confusion if we ever
-                   expose the default environment for session (which arguably
-                   would be useful in many ways).   -->
-      <desc>
-        The set of environment changes.  They are in putenv format, i.e.
-        "NAME=VALUE" for setting and "NAME" for unsetting.
+    <attribute name="environmentChanges" type="wstring" safearray="yes">
+      <desc>
+        The set of scheduled environment changes to the base environment of the
+        session.  They are in putenv format, i.e. "VAR=VALUE" for setting and
+        "VAR" for unsetting.  One entry per variable (change).  The changes are
+        applied when creating new guest processes.
+
+        This is writable, so to undo all the scheduled changes, assign it an
+        empty array.
+      </desc>
+    </attribute>
+    <attribute name="environmentBase" type="wstring" safearray="yes" readonly="yes">
+      <desc>
+        The base environment of the session.  They are on the "VAR=VALUE" form,
+        one array entry per variable.
+        <!-- @todo/TODO/FIXME: This doesn't end up in the PDF.
+        <result name="VBOX_E_NOT_SUPPORTED">If the guest additions does not
+          support the session base environment feature.  Support for this was
+          introduced with protocol version XXX.</result>
+        <result name="VBOX_E_INVALID_OBJECT_STATE">If the guest additions has
+          yet to report the session base environment.</result> -->
+
+        Access fails with VBOX_E_NOT_SUPPORTED if the guest additions does not
+        support the session base environment feature.  Support for this was
+        introduced with protocol version XXXX.
+
+        Access fails with VBOX_E_INVALID_OBJECT_STATE if the guest additions
+        has yet to report the session base environment.
       </desc>
     </attribute>
@@ -11110,8 +11157,9 @@
     </method>
 
-    <method name="environmentSet">
+    <method name="environmentScheduleSet">
       <desc>
         Schedules setting an environment variable when creating the next guest
-        process.  This affects the <link to="IGuestSession::environment"/> attribute.
+        process.  This affects the <link to="IGuestSession::environmentChanges"/>
+        attribute.
       </desc>
       <param name="name" type="wstring" dir="in">
@@ -11124,13 +11172,57 @@
     </method>
 
-    <method name="environmentUnset">
+    <method name="environmentScheduleUnset">
       <desc>
         Schedules unsetting (removing) an environment variable when creating
-        the next guest process.  This affects the <link to="IGuestSession::environment"/>
-        attribute.
+        the next guest process.  This affects the
+        <link to="IGuestSession::environmentChanges"/> attribute.
       </desc>
       <param name="name" type="wstring" dir="in">
         <desc>Name of the environment variable to unset.  This cannot be empty
           nor can it contain any equal signs.</desc>
+      </param>
+    </method>
+
+    <method name="environmentGetBaseVariable">
+      <desc>
+        Gets an environment variable from the session's base environment
+        (<link to="IGuestSession::environmentBase"/>).
+
+        <result name="VBOX_E_NOT_SUPPORTED">If the guest additions does not
+          support the session base environment feature.  Support for this was
+          introduced with protocol version XXXX.</result>
+        <result name="VBOX_E_INVALID_OBJECT_STATE">If the guest additions has
+          yet to report the session base environment.</result>
+      </desc>
+      <param name="name" type="wstring" dir="in">
+        <desc>Name of the environment variable to   get.This cannot be empty
+          nor can it contain any equal signs.</desc>
+      </param>
+      <param name="value" type="wstring" dir="return">
+        <desc>
+          The value of the variable.  Empty if not found.  To deal with
+          variables that may have empty values, use
+          <link to="IGuestSession::environmentDoesBaseVariableExist"/>.
+        </desc>
+      </param>
+    </method>
+
+    <method name="environmentDoesBaseVariableExist">
+      <desc>
+        Checks if the given environment variable exists in the session's base
+        environment (<link to="IGuestSession::environmentBase"/>).
+
+        <result name="VBOX_E_NOT_SUPPORTED">If the guest additions does not
+          support the session base environment feature.  Support for this was
+          introduced with protocol version XXXX.</result>
+        <result name="VBOX_E_INVALID_OBJECT_STATE">If the guest additions has
+          yet to report the session base environment.</result>
+      </desc>
+      <param name="name" type="wstring" dir="in">
+        <desc>Name of the environment variable to look for.  This cannot be
+          empty nor can it contain any equal signs.</desc>
+      </param>
+      <param name="exists" type="boolean" dir="return">
+        <desc>TRUE if the variable exists, FALSE if not.</desc>
       </param>
     </method>
@@ -11432,13 +11524,16 @@
         </desc>
       </param>
-      <param name="environment" type="wstring" dir="in" safearray="yes">
+      <param name="environmentChanges" type="wstring" dir="in" safearray="yes">
         <desc>
           Set of environment changes to complement
-          <link to="IGuestSession::environment"/>.  Takes precedence over
-          the session ones.  The changes are in putenv format, i.e.
-          "NAME=VALUE" for setting and "NAME" for unsetting.
-
-          The changes are applied to the standard environment of the
-          impersonated guest user when creating the process.
+          <link to="IGuestSession::environmentChanges"/>.  Takes precedence
+          over the session ones.  The changes are in putenv format, i.e.
+          "VAR=VALUE" for setting and "VAR" for unsetting.
+
+          The changes are applied to the base environment of the impersonated
+          guest user (<link to="IGuestSession::environmentBase"/>) when
+          creating the process.  (This is done on the guest side of things in
+          order to be compatible with older guest additions.  That is one of
+          the motivations for not passing in the whole environment here.)
         </desc>
       </param>
@@ -11488,13 +11583,16 @@
         </desc>
       </param>
-      <param name="environment" type="wstring" dir="in" safearray="yes">
+      <param name="environmentChanges" type="wstring" dir="in" safearray="yes">
         <desc>
           Set of environment changes to complement
-          <link to="IGuestSession::environment"/>.  Takes precedence over
-          the session ones.  The changes are in putenv format, i.e.
-          "NAME=VALUE" for setting and "NAME" for unsetting.
-
-          The changes are applied to the standard environment of the
-          impersonated guest user when creating the process.
+          <link to="IGuestSession::environmentChanges"/>.  Takes precedence
+          over the session ones.  The changes are in putenv format, i.e.
+          "VAR=VALUE" for setting and "VAR" for unsetting.
+
+          The changes are applied to the base environment of the impersonated
+          guest user (<link to="IGuestSession::environmentBase"/>) when
+          creating the process.  (This is done on the guest side of things in
+          order to be compatible with older guest additions.  That is one of
+          the motivations for not passing in the whole environment here.)
         </desc>
       </param>
@@ -11688,5 +11786,5 @@
   <interface
     name="IProcess" extends="$unknown"
-    uuid="5a4fe06d-8cb1-40ff-ac9e-9676e32f706e"
+    uuid="064cf1ca-4c0f-50b5-8f8e-e8b4bfa76c33"
     wsmap="managed"
     >
@@ -11701,12 +11799,6 @@
     </attribute>
     <attribute name="environment" type="wstring" readonly="yes" safearray="yes">
-      <!-- r=bird: Would probably be a great idea to rename this attribute as
-                   it is misleading and will cause worse confusion if we ever
-                   expose the initial environment for processes.  -->
-      <desc>
-        The set of environment changes appled to the default environment when
-        starting the process.  The format is putenv style, i.e. "NAME=VALUE"
-        for variables that should be set and "NAME" for values that should be
-        unset (removed).  See also <link to="IGuestSession::environment"/>.
+      <desc>
+        The initial process environment.  Not yet implemented.
       </desc>
     </attribute>
@@ -11883,5 +11975,5 @@
   <interface
     name="IGuestProcess" extends="IProcess"
-    uuid="dfa39a36-5d43-4840-a025-67ea956b3111"
+    uuid="1f3c2d60-4c09-d824-4ca1-579a2bda858f"
     wsmap="managed"
     >
@@ -12491,29 +12583,17 @@
         the session object via <link to="IGuest::createSession"/>. Anonymous
         sessions, that is, sessions without specifying a valid
-        user account in the guest are not allowed due to security reasons.
-
-        There can be a maximum of 32 sessions at once per VM. Each session keeps
-        track of its started guest processes, opened guest files or guest directories.
-        To work on guest files or directories a guest session offers methods to open
-        or create such objects (see <link to="IGuestSession::fileOpen"/> or
-        <link to="IGuestSession::directoryOpen"/> for example).
-
-        There can be up to 2048 objects (guest processes, files or directories)
-        a time per guest session. Exceeding the limit will result in an appropriate
-        error message.
-
-        When done with either of these objects, including the guest session itself,
-        use the appropriate close() method to let the object do its cleanup work.
-
-        Every guest session has its own environment variable block which gets
-        automatically applied when starting a new guest process via
-        <link to="IGuestSession::processCreate"/> or <link to="IGuestSession::processCreateEx"/>.
-        To override (or unset) certain environment variables already set by the
-        guest session, one can specify a per-process environment block when using
-        one of the both above mentioned process creation calls.
-
-        Closing a session via <link to="IGuestSession::close" /> will try to close
-        all the mentioned objects above unless these objects are still used by
-        a client.
+        user account in the guest are not allowed reasons of security.
+
+        There can be a maximum of 32 sessions at once per VM.  An error will
+        be returned if this has been reached. <!-- This should actually read:
+        VBOX_E_IPRT_ERROR will be return if this limit has been reached.
+        However, keep in mind that VBOX_E_IPRT_ERROR can be returned for about
+        88 unrelated reasons, so you don't know what happend unless you parse
+        the error text. (bird) -->
+<!-- @todo r=bird: Seriously, add an dedicated VBOX_E_MAX_GUEST_SESSIONS status
+for this condition.  Do the same for all other maximums and things that could be
+useful to the API client. -->
+
+        For more information please consult <link to="IGuestSession"/>
       </desc>
       <param name="user" type="wstring" dir="in">
Index: /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 55590)
+++ /trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 55591)
@@ -26,4 +26,5 @@
 #include <iprt/env.h>
 #include <iprt/semaphore.h>
+#include <iprt/cpp/utils.h>
 
 #include <VBox/com/com.h>
@@ -78,4 +79,5 @@
     GuestEnvironmentBase(void)
         : m_hEnv(NIL_RTENV)
+        , m_cRefs(1)
     { }
 
@@ -85,4 +87,5 @@
     virtual ~GuestEnvironmentBase(void)
     {
+        Assert(m_cRefs <= 1);
         int rc = RTEnvDestroy(m_hEnv); AssertRC(rc);
         m_hEnv = NIL_RTENV;
@@ -90,11 +93,46 @@
 
     /**
-     * Initialize this as a normal environment block.
-     * @returns IPRT status code.
-     */
-    int initNormal(void)
-    {
-        AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
-        return RTEnvCreate(&m_hEnv);
+     * Retains a reference to this object.
+     * @returns New reference count.
+     * @remarks Sharing an object is currently only safe if no changes are made to
+     *          it because RTENV does not yet implement any locking.  For the only
+     *          purpose we need this, implementing IGuestProcess::environment by
+     *          using IGuestSession::environmentBase, that's fine as the session
+     *          base environment is immutable.
+     */
+    uint32_t retain(void)
+    {
+        uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
+        Assert(cRefs > 1); Assert(cRefs < _1M);
+        return cRefs;
+
+    }
+    /** Useful shortcut. */
+    uint32_t retainConst(void) const { return unconst(this)->retain(); }
+
+    /**
+     * Releases a reference to this object, deleting the object when reaching zero.
+     * @returns New reference count.
+     */
+    uint32_t release(void)
+    {
+        uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
+        Assert(cRefs < _1M);
+        if (cRefs == 0)
+            delete this;
+        return cRefs;
+    }
+
+    /** Useful shortcut. */
+    uint32_t releaseConst(void) const { return unconst(this)->retain(); }
+
+    /**
+     * Checks if the environment has been successfully initialized or not.
+     *
+     * @returns @c true if initialized, @c false if not.
+     */
+    bool isInitialized(void) const
+    {
+        return m_hEnv != NIL_RTENV;
     }
 
@@ -167,4 +205,19 @@
         return VINF_SUCCESS;
     }
+
+    /**
+     * Applies the changes from another environment to this.
+     *
+     * @returns IPRT status code.
+     * @param   rChanges        Reference to an environment which variables will be
+     *                          imported and, if it's a change record, schedule
+     *                          variable unsets will be applied.
+     * @sa      RTEnvApplyChanges
+     */
+    int applyChanges(const GuestEnvironmentBase &rChanges)
+    {
+        return RTEnvApplyChanges(m_hEnv, rChanges.m_hEnv);
+    }
+
 
     /**
@@ -219,4 +272,17 @@
 
     /**
+     * Checks if the given variable exists.
+     *
+     * @returns @c true if it exists, @c false if not or if it's an scheduled unset
+     *          in a environment change record.
+     * @param   rName               The variable name.
+     * @sa      RTEnvExistEx
+     */
+    bool doesVariableExist(const com::Utf8Str &rName) const
+    {
+        return RTEnvExistEx(m_hEnv, rName.c_str());
+    }
+
+    /**
      * Set an environment variable.
      *
@@ -243,9 +309,5 @@
     }
 
-#if 0
-private:
-    /* No copy operator. */
-    GuestEnvironmentBase(const GuestEnvironmentBase &) { throw E_FAIL; }
-#else
+protected:
     /**
      * Copy constructor.
@@ -259,7 +321,5 @@
             throw (Global::vboxStatusCodeToCOM(rc));
     }
-#endif
-
-protected:
+
     /**
      * Common clone/copy method with type conversion abilities.
@@ -304,9 +364,10 @@
 
     /** The environment change record. */
-    RTENV       m_hEnv;
-};
-
-
-#if 0 /* Not currently used. */
+    RTENV               m_hEnv;
+    /** Reference counter. */
+    uint32_t volatile   m_cRefs;
+};
+
+
 /**
  * Wrapper around the RTEnv API for a normal environment.
@@ -364,5 +425,4 @@
     }
 };
-#endif /* unused */
 
 
@@ -548,5 +608,5 @@
     ProcessArguments            mArguments;
     /** The process environment change record.  */
-    GuestEnvironmentChanges     mEnvironment;
+    GuestEnvironmentChanges     mEnvironmentChanges;
     /** Process creation flags. */
     uint32_t                    mFlags;
@@ -980,12 +1040,23 @@
 protected:
 
-    /**
-     * Commom parameters for all derived objects, when then have
-     * an own mData structure to keep their specific data around.
-     */
-
+    /** @name Common parameters for all derived objects.  They have their own
+     * mData structure to keep their specific data around.
+     * @{ */
     /** Pointer to parent session. Per definition
      *  this objects *always* lives shorter than the
-     *  parent. */
+     *  parent.
+     * @todo r=bird: When wanting to use mSession in the
+     * IGuestProcess::getEnvironment() implementation I wanted to access
+     * GuestSession::mData::mpBaseEnvironment.  Seeing the comment in
+     * GuestProcess::terminate() saying:
+     *      "Now only API clients still can hold references to it."
+     * and recalling seeing similar things in VirtualBox.xidl or some such place,
+     * I'm wondering how this "per definition" behavior is enforced.  Is there any
+     * GuestProcess:uninit() call or similar magic that invalidates objects that
+     * GuestSession loses track of in place like GuestProcess::terminate() that I've
+     * failed to spot?
+     *
+     * Please enlighten me.
+     */
     GuestSession            *mSession;
     /** The object ID -- must be unique for each guest
@@ -996,5 +1067,6 @@
      *  for guest files this is the internal file ID. */
     uint32_t                 mObjectID;
-};
-#endif // ____H_GUESTIMPLPRIVATE
-
+    /** @} */
+};
+#endif // !____H_GUESTIMPLPRIVATE
+
Index: /trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 55590)
+++ /trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 55591)
@@ -22,4 +22,6 @@
 #include "GuestProcessWrap.h"
 
+#include <iprt/cpp/utils.h>
+
 class Console;
 class GuestSession;
@@ -37,5 +39,6 @@
     DECLARE_EMPTY_CTOR_DTOR(GuestProcess)
 
-    int     init(Console *aConsole, GuestSession *aSession, ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo);
+    int     init(Console *aConsole, GuestSession *aSession, ULONG aProcessID,
+                 const GuestProcessStartupInfo &aProcInfo, const GuestEnvironment *pBaseEnv);
     void    uninit(void);
     HRESULT FinalConstruct(void);
@@ -137,4 +140,10 @@
         /** The process startup information. */
         GuestProcessStartupInfo  mProcess;
+        /** Reference to the immutable session base environment. NULL if the
+         * environment feature isn't supported.
+         * @remarks If there is proof that the uninit order of GuestSession and
+         *          this class is what GuestObjectBase claims, then this isn't
+         *          strictly necessary. */
+        GuestEnvironment const  *mpSessionBaseEnv;
         /** Exit code if process has been terminated. */
         LONG                     mExitCode;
@@ -146,4 +155,15 @@
          *  returned from the guest side. */
         int                      mLastError;
+
+        Data(void) : mpSessionBaseEnv(NULL)
+        { }
+        ~Data(void)
+        {
+            if (mpSessionBaseEnv)
+            {
+                mpSessionBaseEnv->releaseConst();
+                mpSessionBaseEnv = NULL;
+            }
+        }
     } mData;
 };
Index: /trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 55590)
+++ /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 55591)
@@ -268,6 +268,7 @@
     HRESULT getProtocolVersion(ULONG *aProtocolVersion);
     HRESULT getStatus(GuestSessionStatus_T *aStatus);
-    HRESULT getEnvironment(std::vector<com::Utf8Str> &aEnvironment);
-    HRESULT setEnvironment(const std::vector<com::Utf8Str> &aEnvironment);
+    HRESULT getEnvironmentChanges(std::vector<com::Utf8Str> &aEnvironmentChanges);
+    HRESULT setEnvironmentChanges(const std::vector<com::Utf8Str> &aEnvironmentChanges);
+    HRESULT getEnvironmentBase(std::vector<com::Utf8Str> &aEnvironmentBase);
     HRESULT getProcesses(std::vector<ComPtr<IGuestProcess> > &aProcesses);
     HRESULT getDirectories(std::vector<ComPtr<IGuestDirectory> > &aDirectories);
@@ -312,7 +313,11 @@
     HRESULT directorySetACL(const com::Utf8Str &aPath,
                              const com::Utf8Str &aAcl);
-    HRESULT environmentSet(const com::Utf8Str &aName,
-                           const com::Utf8Str &aValue);
-    HRESULT environmentUnset(const com::Utf8Str &aName);
+    HRESULT environmentScheduleSet(const com::Utf8Str &aName,
+                                   const com::Utf8Str &aValue);
+    HRESULT environmentScheduleUnset(const com::Utf8Str &aName);
+    HRESULT environmentGetBaseVariable(const com::Utf8Str &aName,
+                                       com::Utf8Str &aValue);
+    HRESULT environmentDoesBaseVariableExist(const com::Utf8Str &aName,
+                                             BOOL *aExists);
     HRESULT fileCreateTemp(const com::Utf8Str &aTemplateName,
                            ULONG aMode,
@@ -469,5 +474,9 @@
         /** The set of environment changes for the session for use when
          *  creating new guest processes. */
-        GuestEnvironmentChanges     mEnvironment;
+        GuestEnvironmentChanges     mEnvironmentChanges;
+        /** Pointer to the immutable base environment for the session.
+         * @note This is not allocated until the guest reports it to the host. It is
+         *       also shared with child processes. */
+        GuestEnvironment const     *mpBaseEnvironment;
         /** Directory objects bound to this session. */
         SessionDirectories          mDirectories;
@@ -488,4 +497,22 @@
          *  returned from the guest side. */
         int                         mRC;
+
+        Data(void)
+            : mpBaseEnvironment(NULL)
+        { }
+        Data(const Data &rThat)
+            : mCredentials(rThat.mCredentials)
+            , mSession(rThat.mSession)
+            , mStatus(rThat.mStatus)
+            , mEnvironmentChanges(rThat.mEnvironmentChanges)
+            , mpBaseEnvironment(NULL)
+            , mDirectories(rThat.mDirectories)
+            , mFiles(rThat.mFiles)
+            , mProcesses(rThat.mProcesses)
+            , mProtocolVersion(rThat.mProtocolVersion)
+            , mTimeout(rThat.mTimeout)
+            , mNumObjects(rThat.mNumObjects)
+            , mRC(rThat.mRC)
+        { }
     } mData;
 };
Index: /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 55590)
+++ /trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 55591)
@@ -162,9 +162,9 @@
 /////////////////////////////////////////////////////////////////////////////
 
-int GuestProcess::init(Console *aConsole, GuestSession *aSession,
-                       ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo)
-{
-    LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32\n",
-                     aConsole, aSession, aProcessID));
+int GuestProcess::init(Console *aConsole, GuestSession *aSession, ULONG aProcessID,
+                       const GuestProcessStartupInfo &aProcInfo, const GuestEnvironment *pBaseEnv)
+{
+    LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32 pBaseEnv=%p\n",
+                     aConsole, aSession, aProcessID, pBaseEnv));
 
     AssertPtrReturn(aConsole, VERR_INVALID_POINTER);
@@ -237,4 +237,7 @@
     {
         mData.mProcess = aProcInfo;
+        mData.mpSessionBaseEnv = pBaseEnv;
+        if (pBaseEnv)
+            pBaseEnv->retainConst();
         mData.mExitCode = 0;
         mData.mPID = 0;
@@ -274,4 +277,10 @@
      *       case of failure. */
 
+    if (mData.mpSessionBaseEnv)
+    {
+        mData.mpSessionBaseEnv->releaseConst();
+        mData.mpSessionBaseEnv = NULL;
+    }
+
     baseUninit();
 
@@ -298,13 +307,32 @@
 HRESULT GuestProcess::getEnvironment(std::vector<com::Utf8Str> &aEnvironment)
 {
-#ifndef VBOX_WITH_GUEST_CONTROL
+#ifndef VBOX_WTIH_GUEST_CONTROL
     ReturnComNotImplemented();
 #else
-    LogFlowThisFuncEnter();
-
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    mData.mProcess.mEnvironment.queryPutEnvArray(&aEnvironment);
-    return S_OK;
-#endif /* VBOX_WITH_GUEST_CONTROL */
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);  /* (Paranoia since both environment objects are immutable.) */
+    HRESULT hrc;
+    if (mData.mpSessionBaseEnv)
+    {
+        int vrc;
+        if (mData.mProcess.mEnvironmentChanges.count() == 0)
+            vrc = mData.mpSessionBaseEnv->queryPutEnvArray(&aEnvironment);
+        else
+        {
+            GuestEnvironment TmpEnv;
+            vrc = TmpEnv.copy(*mData.mpSessionBaseEnv);
+            if (RT_SUCCESS(vrc))
+            {
+                vrc = TmpEnv.applyChanges(mData.mProcess.mEnvironmentChanges);
+                if (RT_SUCCESS(rc))
+                    vrc = TmpEnv.queryPutEnvArray(&aEnvironment);
+            }
+        }
+        hrc = Global::vboxStatusCodeToCOM(vrc);
+    }
+    else
+        hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
+    LogFlowThisFuncLeave();
+    return hrc;
+#endif
 }
 
@@ -1057,5 +1085,5 @@
     char   *pszzEnvBlock;
     if (RT_SUCCESS(vrc))
-        vrc = mData.mProcess.mEnvironment.queryUtf8Block(&pszzEnvBlock, &cbEnvBlock);
+        vrc = mData.mProcess.mEnvironmentChanges.queryUtf8Block(&pszzEnvBlock, &cbEnvBlock);
 
     if (RT_SUCCESS(vrc))
@@ -1069,5 +1097,5 @@
         paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
         paParms[i++].setPointer(pszArgs, (uint32_t)cbArgs);
-        paParms[i++].setUInt32(mData.mProcess.mEnvironment.count());
+        paParms[i++].setUInt32(mData.mProcess.mEnvironmentChanges.count());
         paParms[i++].setUInt32((uint32_t)cbEnvBlock);
         paParms[i++].setPointer(pszzEnvBlock, (uint32_t)cbEnvBlock);
@@ -1109,5 +1137,5 @@
         }
 
-        mData.mProcess.mEnvironment.freeUtf8Block(pszzEnvBlock);
+        mData.mProcess.mEnvironmentChanges.freeUtf8Block(pszzEnvBlock);
     }
 
Index: /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 55590)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 55591)
@@ -205,5 +205,6 @@
     mData.mStatus = GuestSessionStatus_Undefined;
     mData.mNumObjects = 0;
-    int rc = mData.mEnvironment.initNormal();
+    mData.mpBaseEnvironment = NULL;
+    int rc = mData.mEnvironmentChanges.initChangeRecord();
     if (RT_SUCCESS(rc))
     {
@@ -320,5 +321,12 @@
     mData.mProcesses.clear();
 
-    mData.mEnvironment.reset();
+    mData.mEnvironmentChanges.reset();
+
+    if (mData.mpBaseEnvironment)
+    {
+        GuestEnvironment *pBaseEnv = unconst(mData.mpBaseEnvironment);
+        mData.mpBaseEnvironment = NULL;
+        pBaseEnv->release();
+    }
 
     AssertMsg(mData.mNumObjects == 0,
@@ -462,5 +470,5 @@
 }
 
-HRESULT GuestSession::getEnvironment(std::vector<com::Utf8Str> &aEnvironment)
+HRESULT GuestSession::getEnvironmentChanges(std::vector<com::Utf8Str> &aEnvironmentChanges)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -471,5 +479,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    int vrc = mData.mEnvironment.queryPutEnvArray(&aEnvironment);
+    int vrc = mData.mEnvironmentChanges.queryPutEnvArray(&aEnvironmentChanges);
 
     LogFlowFuncLeaveRC(vrc);
@@ -478,5 +486,5 @@
 }
 
-HRESULT GuestSession::setEnvironment(const std::vector<com::Utf8Str> &aEnvironment)
+HRESULT GuestSession::setEnvironmentChanges(const std::vector<com::Utf8Str> &aEnvironmentChanges)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -487,9 +495,33 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    mData.mEnvironment.reset();
-    int vrc = mData.mEnvironment.applyPutEnvArray(aEnvironment);
+    mData.mEnvironmentChanges.reset();
+    int vrc = mData.mEnvironmentChanges.applyPutEnvArray(aEnvironmentChanges);
 
     LogFlowFuncLeaveRC(vrc);
     return Global::vboxStatusCodeToCOM(vrc);
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
+HRESULT GuestSession::getEnvironmentBase(std::vector<com::Utf8Str> &aEnvironmentBase)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    HRESULT hrc;
+    if (mData.mpBaseEnvironment)
+    {
+        int vrc = mData.mpBaseEnvironment->queryPutEnvArray(&aEnvironmentBase);
+        hrc = Global::vboxStatusCodeToCOM(vrc);
+    }
+    else if (mData.mProtocolVersion < 99999)
+        hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
+    else
+        hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
+
+    LogFlowFuncLeave();
+    return hrc;
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
@@ -1917,5 +1949,5 @@
 
     rc = pProcess->init(mParent->i_getConsole() /* Console */, this /* Session */,
-                        uNewProcessID, procInfo);
+                        uNewProcessID, procInfo, mData.mpBaseEnvironment);
     if (RT_FAILURE(rc))
         return rc;
@@ -2904,5 +2936,5 @@
 }
 
-HRESULT GuestSession::environmentSet(const com::Utf8Str &aName, const com::Utf8Str &aValue)
+HRESULT GuestSession::environmentScheduleSet(const com::Utf8Str &aName, const com::Utf8Str &aValue)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -2917,5 +2949,5 @@
         {
             AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-            int vrc = mData.mEnvironment.setVariable(aName, aValue);
+            int vrc = mData.mEnvironmentChanges.setVariable(aName, aValue);
             if (RT_SUCCESS(vrc))
                 hrc = S_OK;
@@ -2934,5 +2966,5 @@
 }
 
-HRESULT GuestSession::environmentUnset(const com::Utf8Str &aName)
+HRESULT GuestSession::environmentScheduleUnset(const com::Utf8Str &aName)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -2946,9 +2978,79 @@
         {
             AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-            int vrc = mData.mEnvironment.unsetVariable(aName);
+            int vrc = mData.mEnvironmentChanges.unsetVariable(aName);
             if (RT_SUCCESS(vrc))
                 hrc = S_OK;
             else
                 hrc = setErrorVrc(vrc);
+        }
+        else
+            hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
+    }
+    else
+        hrc = setError(E_INVALIDARG, tr("No variable name specified"));
+
+    LogFlowThisFuncLeave();
+    return hrc;
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
+HRESULT GuestSession::environmentGetBaseVariable(const com::Utf8Str &aName, com::Utf8Str &aValue)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+    HRESULT hrc;
+    if (RT_LIKELY(aName.isNotEmpty()))
+    {
+        if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
+        {
+            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+            if (mData.mpBaseEnvironment)
+            {
+                int vrc = mData.mpBaseEnvironment->getVariable(aName, &aValue);
+                if (RT_SUCCESS(vrc))
+                    hrc = S_OK;
+                else
+                    hrc = setErrorVrc(vrc);
+            }
+            else if (mData.mProtocolVersion < 99999)
+                hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
+            else
+                hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
+        }
+        else
+            hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
+    }
+    else
+        hrc = setError(E_INVALIDARG, tr("No variable name specified"));
+
+    LogFlowThisFuncLeave();
+    return hrc;
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
+HRESULT GuestSession::environmentDoesBaseVariableExist(const com::Utf8Str &aName, BOOL *aExists)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+    *aExists = FALSE;
+    HRESULT hrc;
+    if (RT_LIKELY(aName.isNotEmpty()))
+    {
+        if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
+        {
+            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+            if (mData.mpBaseEnvironment)
+            {
+                hrc = S_OK;
+                *aExists = mData.mpBaseEnvironment->doesVariableExist(aName);
+            }
+            else if (mData.mProtocolVersion < 99999)
+                hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
+            else
+                hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
         }
         else
@@ -3345,7 +3447,7 @@
        the caller, giving priority to the latter.  The changes are putenv style
        and will be applied to the standard environment for the guest user. */
-    int vrc = procInfo.mEnvironment.copy(mData.mEnvironment);
+    int vrc = procInfo.mEnvironmentChanges.copy(mData.mEnvironmentChanges);
     if (RT_SUCCESS(vrc))
-        vrc = procInfo.mEnvironment.applyPutEnvArray(aEnvironment);
+        vrc = procInfo.mEnvironmentChanges.applyPutEnvArray(aEnvironment);
     if (RT_SUCCESS(vrc))
     {
Index: /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py
===================================================================
--- /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py	(revision 55590)
+++ /trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py	(revision 55591)
@@ -1070,5 +1070,5 @@
     def testGuestCtrlSessionEnvironment(self, oSession, oTxsSession, oTestVm): # pylint: disable=R0914
         """
-        Tests the guest session environment.
+        Tests the guest session environment changes.
         """
 
@@ -1112,4 +1112,7 @@
         ];
 
+        # The IGuestSession::environment attribute changed late in 5.0 development.
+        sEnvironmentChangesAttr = 'environmentChanges' if self.oTstDrv.fpApiVer >= 5.0 else 'environment';
+
         # Parameters.
         fRc = True;
@@ -1127,5 +1130,5 @@
                 break;
             # Make sure environment is empty.
-            curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, 'environment');
+            curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, sEnvironmentChangesAttr);
             reporter.log2('Test #%d: Environment initially has %d elements' % (i, len(curEnv)));
             if len(curEnv) != 0:
@@ -1145,9 +1148,12 @@
                                   % (i, strKey, strValue, len(aElems)));
                     try:
-                        curGuestSession.environmentSet(strKey, strValue); # No return (e.g. boolean) value available thru wrapper.
+                        if self.oTstDrv.fpApiVer >= 5.0:
+                            curGuestSession.environmentScheduleSet(strKey, strValue);
+                        else:
+                            curGuestSession.environmentSet(strKey, strValue);
                     except:
                         # Setting environment variables might fail (e.g. if empty name specified). Check.
                         reporter.logXcpt('Test #%d failed: Setting environment variable failed:' % (i,));
-                        curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, 'environment');
+                        curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, sEnvironmentChangesAttr);
                         if len(curEnv) is not curRes.cNumVars:
                             reporter.error('Test #%d failed: Session environment has %d vars, expected %d' \
@@ -1158,5 +1164,5 @@
                             reporter.log('Test #%d: API reported an error (single), good' % (i,));
                     ## @todo environmentGet() has been removed in 5.0 because it's not up to the task of returning all the
-                    ## putenv strings forms and gives the impression that the envrionment is something it isn't. This test
+                    ## putenv strings forms and gives the impression that the environment is something it isn't. This test
                     ## should be rewritten using the attribute.  What's more, there should be an Unset test here, shouldn't
                     ## there?
@@ -1197,5 +1203,5 @@
                     except:
                         # Setting environment variables might fail (e.g. if empty name specified). Check.
-                        curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, 'environment');
+                        curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, sEnvironmentChangesAttr);
                         if len(curEnv) is not curRes.cNumVars:
                             reporter.error('Test #%d failed: Session environment has %d vars, expected %d (array)' \
@@ -1207,5 +1213,5 @@
                 ## @todo Get current system environment and add it to curRes.cNumVars before comparing!
                 reporter.log('Test #%d: Environment size' % (i,));
-                curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, 'environment');
+                curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, sEnvironmentChangesAttr);
                 reporter.log2('Test #%d: Environment (%d) -> %s' % (i, len(curEnv), curEnv));
                 if len(curEnv) != curRes.cNumVars:
@@ -1215,6 +1221,6 @@
                     break;
 
-                self.oTstDrv.oVBoxMgr.setArray(curGuestSession, 'environment', []);
-                curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, 'environment');
+                self.oTstDrv.oVBoxMgr.setArray(curGuestSession, sEnvironmentChangesAttr, []);
+                curEnv = self.oTstDrv.oVBoxMgr.getArray(curGuestSession, sEnvironmentChangesAttr);
                 if len(curEnv) is not 0:
                     reporter.error('Test #%d failed: Session environment has %d vars, expected 0');
