1 /*
2  * $Header$
3  *
4  * Copyright 2008 Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  * require a specific license from the United States Government.
9  * It is the responsibility of any person or organization contemplating
10  * export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 #include <windows.h>
28 #include "secure.hxx"
29 
30 extern "C" {
31 #include "cci_debugging.h"
32     }
33 
34 CcOsLock SecureClient::s_lock;
35 DWORD SecureClient::s_refcount = 0;
36 DWORD SecureClient::s_error = 0;
37 HANDLE SecureClient::s_hToken = 0;
38 
39 #include "util.h"
40 
41 #define SC "SecureClient::"
42 
43 DWORD
Attach()44 SecureClient::Attach(
45     )
46 {
47     CcAutoLock AL(s_lock);
48     if (s_hToken) {
49         s_refcount++;
50         return 0;
51     }
52     if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
53                          &s_hToken)) {
54         s_refcount++;
55         s_error = 0;
56     } else {
57         s_hToken = 0;
58         s_error = GetLastError();
59     }
60     return s_error;
61 }
62 
63 DWORD
Detach()64 SecureClient::Detach(
65     )
66 {
67     CcAutoLock AL(s_lock);
68     s_refcount--;
69     if (s_refcount) return 0;
70     if (!s_hToken) return 0;
71     DWORD error = 0;
72     if (!CloseHandle(s_hToken))
73         error = GetLastError();
74     s_hToken = 0;
75     s_error = 0;
76     return error;
77 }
78 
Token(HANDLE & hToken)79 DWORD SecureClient::Token(HANDLE& hToken) {
80     // This function will not do automatic initialization.
81     CcAutoLock AL(s_lock);
82     hToken = 0;
83     if (!s_hToken) {
84         cci_debug_printf("%s no process token initialized (%u)", __FUNCTION__, s_error);
85         return s_error ? s_error : ERROR_INVALID_HANDLE;
86         }
87     else {
88         DWORD status = 0;
89         if (!DuplicateHandle(GetCurrentProcess(), s_hToken,
90                              GetCurrentProcess(), &hToken, 0, FALSE,
91                              DUPLICATE_SAME_ACCESS)) {
92             status = GetLastError();
93             cci_debug_printf("  Could not duplicate handle (%u)", status);
94             }
95         return status;
96         }
97     }
98 
99 void
Start(SecureClient * & s)100 SecureClient::Start(SecureClient*& s) {
101     s = new SecureClient;
102 }
103 
104 void
Stop(SecureClient * & s)105 SecureClient::Stop(SecureClient*& s) {
106     delete s;
107     s = 0;
108 }
109 
110 ///////////////////////////////////////////////////////////////////////////////
111 
112 /* This constructor turns off impersonation.
113  * It is OK for OpenThreadToken to return an error -- that just means impersonation
114  * is off.
115  */
SecureClient()116 SecureClient::SecureClient():
117     m_Error(0),
118     m_hToken(0),
119     m_NeedRestore(false) {
120 
121     HANDLE hThread = GetCurrentThread();
122     HANDLE hThDuplicate;
123 
124     int status  = DuplicateHandle(  GetCurrentProcess(),
125                                     hThread,
126                                     GetCurrentProcess(),
127                                     &hThDuplicate,
128                                     TOKEN_ALL_ACCESS,
129                                     FALSE,
130                                     0);
131     if (!status) return;
132 
133     if (!OpenThreadToken(hThDuplicate, TOKEN_ALL_ACCESS, FALSE, &m_hToken)) {
134         m_Error = GetLastError();
135         return;
136         }
137     if (SetThreadToken(&hThDuplicate, NULL)) {
138         m_NeedRestore = true;
139     } else {
140         m_Error = GetLastError();
141         }
142     CloseHandle(hThDuplicate);
143     }
144 
~SecureClient()145 SecureClient::~SecureClient() {
146     if (m_NeedRestore) {
147         HANDLE hThread = GetCurrentThread();
148         if (!SetThreadToken(&hThread, m_hToken)) {
149             m_Error = cci_check_error(GetLastError());
150             }
151         }
152     if (m_hToken) {
153         if (!CloseHandle(m_hToken)) {
154             m_Error = cci_check_error(GetLastError());
155             }
156         }
157     }
158 
Error()159 DWORD SecureClient::Error() {
160     return m_Error;
161     }