[Spice-devel,vdagent-win,1/6] vdagent: add as_user to run tasks with user privileges

Submitted by Uri Lublin on Nov. 7, 2013, 10:02 p.m.

Details

Message ID 1383861776-25959-2-git-send-email-uril@redhat.com
State Superseded
Headers show

Not browsing as part of any series.

Commit Message

Uri Lublin Nov. 7, 2013, 10:02 p.m.
The class calls Impersonate upon begin(), and Revert
upon end() or destruction.

The user is the current user that is logged in.

 create mode 100644 vdagent/as_user.cpp
 create mode 100644 vdagent/as_user.h

Patch hide | download patch | download mbox

diff --git a/Makefile.am b/Makefile.am
index f907031..768e984 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,8 @@  vdagent_SOURCES =			\
         vdagent/file_xfer.cpp		\
         vdagent/file_xfer.h		\
 	vdagent/vdagent.cpp		\
+	vdagent/as_user.cpp		\
+	vdagent/as_user.h		\
 	$(NULL)

 vdagent_rc.$(OBJEXT): vdagent/vdagent.rc
diff --git a/vdagent/as_user.cpp b/vdagent/as_user.cpp
new file mode 100644
index 0000000..67785eb
--- /dev/null
+++ b/vdagent/as_user.cpp
@@ -0,0 +1,73 @@ 
+/*
+   Copyright (C) 2013 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "vdcommon.h"
+#include "as_user.h"
+
+#include <wtsapi32.h>
+
+AsUser::AsUser(DWORD session_id):
+    _started(false),
+    _session_id(session_id),
+    _token(INVALID_HANDLE_VALUE)
+{
+}
+
+bool AsUser::begin()
+{
+    BOOL ret;
+
+    if (_session_id == (DWORD)-1) {
+        ret = ProcessIdToSessionId(GetCurrentProcessId(), &_session_id);
+        if (!ret) {
+            vd_printf("ProcessIdToSessionId failed %lu", GetLastError());
+            return false;
+        }
+    }
+    if (_token == INVALID_HANDLE_VALUE) {
+        ret = WTSQueryUserToken(_session_id, &_token);
+        if (!ret) {
+            vd_printf("WTSQueryUserToken failed -- %lu", GetLastError());
+        return false;
+        }
+    }
+
+    ret = ImpersonateLoggedOnUser(_token);
+    if (!ret) {
+        vd_printf("ImpersonateLoggedOnUser failed: %lu", GetLastError());
+        return false;
+    }
+
+    _started = true;
+    return true;
+}
+
+void AsUser::end()
+{
+    if (_started) {
+        RevertToSelf();
+        _started = false;
+    }
+}
+
+AsUser::~AsUser()
+{
+    if (_token != INVALID_HANDLE_VALUE) {
+        end();
+        CloseHandle(_token);
+    }
+}
diff --git a/vdagent/as_user.h b/vdagent/as_user.h
new file mode 100644
index 0000000..6243e98
--- /dev/null
+++ b/vdagent/as_user.h
@@ -0,0 +1,38 @@ 
+/*
+   Copyright (C) 2013 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_AS_USER_
+#define _H_AS_USER_
+
+/** AsUser runs a task as the user logged on in session_id.
+ *  Constructor calls Impersonate, Destructor calls Revert, so
+ *  the caller needs not worry about that.
+ */
+class AsUser {
+public:
+    ~AsUser();
+    AsUser(DWORD session_id = (DWORD)-1);
+    bool begin();
+    void end();
+
+private:
+    DWORD _session_id;
+    HANDLE _token;
+    bool _started;
+};
+
+#endif
diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index 6943e5e..40e2290 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -342,6 +342,10 @@ 
 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
+				RelativePath=".\as_user.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\desktop_layout.cpp"
 				>
 			</File>
@@ -372,6 +376,10 @@ 
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
 			<File
+				RelativePath=".\as_user.h"
+				>
+			</File>
+			<File
 				RelativePath=".\desktop_layout.h"
 				>
 			</File>

Comments

On Fri, Nov 08, 2013 at 12:02:51AM +0200, Uri Lublin wrote:
> The class calls Impersonate upon begin(), and Revert
> upon end() or destruction.
> 
> The user is the current user that is logged in.
> 
>  create mode 100644 vdagent/as_user.cpp
>  create mode 100644 vdagent/as_user.h
> 
> diff --git a/Makefile.am b/Makefile.am
> index f907031..768e984 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -35,6 +35,8 @@ vdagent_SOURCES =			\
>          vdagent/file_xfer.cpp		\
>          vdagent/file_xfer.h		\
>  	vdagent/vdagent.cpp		\
> +	vdagent/as_user.cpp		\
> +	vdagent/as_user.h		\
>  	$(NULL)
> 
>  vdagent_rc.$(OBJEXT): vdagent/vdagent.rc
> diff --git a/vdagent/as_user.cpp b/vdagent/as_user.cpp
> new file mode 100644
> index 0000000..67785eb
> --- /dev/null
> +++ b/vdagent/as_user.cpp
> @@ -0,0 +1,73 @@
> +/*
> +   Copyright (C) 2013 Red Hat, Inc.
> +
> +   This program is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU General Public License as
> +   published by the Free Software Foundation; either version 2 of
> +   the License, or (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include "vdcommon.h"
> +#include "as_user.h"
> +
> +#include <wtsapi32.h>
> +
> +AsUser::AsUser(DWORD session_id):
> +    _started(false),
> +    _session_id(session_id),
> +    _token(INVALID_HANDLE_VALUE)
> +{
> +}
> +
> +bool AsUser::begin()
> +{
> +    BOOL ret;
> +
> +    if (_session_id == (DWORD)-1) {
> +        ret = ProcessIdToSessionId(GetCurrentProcessId(), &_session_id);
> +        if (!ret) {
> +            vd_printf("ProcessIdToSessionId failed %lu", GetLastError());
> +            return false;
> +        }
> +    }
> +    if (_token == INVALID_HANDLE_VALUE) {
> +        ret = WTSQueryUserToken(_session_id, &_token);
> +        if (!ret) {
> +            vd_printf("WTSQueryUserToken failed -- %lu", GetLastError());
> +        return false;
> +        }
> +    }
> +
> +    ret = ImpersonateLoggedOnUser(_token);
> +    if (!ret) {
> +        vd_printf("ImpersonateLoggedOnUser failed: %lu", GetLastError());
> +        return false;
> +    }
> +
> +    _started = true;
> +    return true;
> +}
> +
> +void AsUser::end()
> +{
> +    if (_started) {
> +        RevertToSelf();
> +        _started = false;

> +    }
> +}
> +
> +AsUser::~AsUser()
> +{
> +    if (_token != INVALID_HANDLE_VALUE) {
> +        end();
> +        CloseHandle(_token);
> +    }

I'd tend to call end() unconditionally here as in the rest of the code,
it's _started which controls whether begin() was called or not, not _token
(even though I agree that there are no cases when _token is
INVALID_HANDLE_VALUE and when we need to call end()).

Looks good otherwise.

Christophe

> +}
> diff --git a/vdagent/as_user.h b/vdagent/as_user.h
> new file mode 100644
> index 0000000..6243e98
> --- /dev/null
> +++ b/vdagent/as_user.h
> @@ -0,0 +1,38 @@
> +/*
> +   Copyright (C) 2013 Red Hat, Inc.
> +
> +   This program is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU General Public License as
> +   published by the Free Software Foundation; either version 2 of
> +   the License, or (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#ifndef _H_AS_USER_
> +#define _H_AS_USER_
> +
> +/** AsUser runs a task as the user logged on in session_id.
> + *  Constructor calls Impersonate, Destructor calls Revert, so
> + *  the caller needs not worry about that.
> + */
> +class AsUser {
> +public:
> +    ~AsUser();
> +    AsUser(DWORD session_id = (DWORD)-1);
> +    bool begin();
> +    void end();
> +
> +private:
> +    DWORD _session_id;
> +    HANDLE _token;
> +    bool _started;
> +};
> +
> +#endif
> diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
> index 6943e5e..40e2290 100644
> --- a/vdagent/vdagent.vcproj
> +++ b/vdagent/vdagent.vcproj
> @@ -342,6 +342,10 @@
>  			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>  			>
>  			<File
> +				RelativePath=".\as_user.cpp"
> +				>
> +			</File>
> +			<File
>  				RelativePath=".\desktop_layout.cpp"
>  				>
>  			</File>
> @@ -372,6 +376,10 @@
>  			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>  			>
>  			<File
> +				RelativePath=".\as_user.h"
> +				>
> +			</File>
> +			<File
>  				RelativePath=".\desktop_layout.h"
>  				>
>  			</File>
> -- 
> 1.8.3.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel