blob: afbdd067123cdb6fc30267b78034d4256afee3ac [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- Registry.cxx
20
21#include <rfb_win32/Registry.h>
22#include <rfb_win32/Security.h>
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000023#include <rdr/MemOutStream.h>
Peter Åstrandd6b96702008-12-09 10:36:16 +000024#include <rdr/HexOutStream.h>
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000025#include <rdr/HexInStream.h>
26#include <stdlib.h>
27#include <rfb/LogWriter.h>
28
29// These flags are required to control access control inheritance,
30// but are not defined by VC6's headers. These definitions comes
31// from the Microsoft Platform SDK.
32#ifndef PROTECTED_DACL_SECURITY_INFORMATION
33#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L)
34#endif
35#ifndef UNPROTECTED_DACL_SECURITY_INFORMATION
36#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L)
37#endif
38
39
40using namespace rfb;
41using namespace rfb::win32;
42
43
44static LogWriter vlog("Registry");
45
46
47RegKey::RegKey() : key(0), freeKey(false), valueNameBufLen(0) {}
48
49RegKey::RegKey(const HKEY k) : key(0), freeKey(false), valueNameBufLen(0) {
50 LONG result = RegOpenKeyEx(k, 0, 0, KEY_ALL_ACCESS, &key);
51 if (result != ERROR_SUCCESS)
52 throw rdr::SystemException("RegOpenKeyEx(HKEY)", result);
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010053 vlog.debug("duplicated %p to %p", k, key);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000054 freeKey = true;
55}
56
57RegKey::RegKey(const RegKey& k) : key(0), freeKey(false), valueNameBufLen(0) {
58 LONG result = RegOpenKeyEx(k.key, 0, 0, KEY_ALL_ACCESS, &key);
59 if (result != ERROR_SUCCESS)
60 throw rdr::SystemException("RegOpenKeyEx(RegKey&)", result);
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010061 vlog.debug("duplicated %p to %p", k.key, key);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000062 freeKey = true;
63}
64
65RegKey::~RegKey() {
66 close();
67}
68
69
70void RegKey::setHKEY(HKEY k, bool fK) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010071 vlog.debug("setHKEY(%p,%d)", k, (int)fK);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000072 close();
73 freeKey = fK;
74 key = k;
75}
76
77
78bool RegKey::createKey(const RegKey& root, const TCHAR* name) {
79 close();
80 LONG result = RegCreateKey(root.key, name, &key);
81 if (result != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010082 vlog.error("RegCreateKey(%p, %s): %lx", root.key, name, result);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000083 throw rdr::SystemException("RegCreateKeyEx", result);
84 }
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010085 vlog.debug("createKey(%p,%s) = %p", root.key, (const char*)CStr(name), key);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000086 freeKey = true;
87 return true;
88}
89
90void RegKey::openKey(const RegKey& root, const TCHAR* name, bool readOnly) {
91 close();
92 LONG result = RegOpenKeyEx(root.key, name, 0, readOnly ? KEY_READ : KEY_ALL_ACCESS, &key);
93 if (result != ERROR_SUCCESS)
94 throw rdr::SystemException("RegOpenKeyEx (open)", result);
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010095 vlog.debug("openKey(%p,%s,%s) = %p", root.key, (const char*)CStr(name),
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000096 readOnly ? "ro" : "rw", key);
97 freeKey = true;
98}
99
100void RegKey::setDACL(const PACL acl, bool inherit) {
101 DWORD result;
Pierre Ossmanfc08bee2016-01-12 12:32:15 +0100102 if ((result = SetSecurityInfo(key, SE_REGISTRY_KEY,
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000103 DACL_SECURITY_INFORMATION |
104 (inherit ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION),
105 0, 0, acl, 0)) != ERROR_SUCCESS)
106 throw rdr::SystemException("RegKey::setDACL failed", result);
107}
108
109void RegKey::close() {
110 if (freeKey) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100111 vlog.debug("RegCloseKey(%p)", key);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000112 RegCloseKey(key);
113 key = 0;
114 }
115}
116
117void RegKey::deleteKey(const TCHAR* name) const {
118 LONG result = RegDeleteKey(key, name);
119 if (result != ERROR_SUCCESS)
120 throw rdr::SystemException("RegDeleteKey", result);
121}
122
123void RegKey::deleteValue(const TCHAR* name) const {
124 LONG result = RegDeleteValue(key, name);
125 if (result != ERROR_SUCCESS)
126 throw rdr::SystemException("RegDeleteValue", result);
127}
128
129void RegKey::awaitChange(bool watchSubTree, DWORD filter, HANDLE event) const {
130 LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, event, event != 0);
131 if (result != ERROR_SUCCESS)
132 throw rdr::SystemException("RegNotifyChangeKeyValue", result);
133}
134
135
136RegKey::operator HKEY() const {return key;}
137
138
139void RegKey::setExpandString(const TCHAR* valname, const TCHAR* value) const {
140 LONG result = RegSetValueEx(key, valname, 0, REG_EXPAND_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
141 if (result != ERROR_SUCCESS) throw rdr::SystemException("setExpandString", result);
142}
143
144void RegKey::setString(const TCHAR* valname, const TCHAR* value) const {
145 LONG result = RegSetValueEx(key, valname, 0, REG_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR));
146 if (result != ERROR_SUCCESS) throw rdr::SystemException("setString", result);
147}
148
149void RegKey::setBinary(const TCHAR* valname, const void* value, int length) const {
150 LONG result = RegSetValueEx(key, valname, 0, REG_BINARY, (const BYTE*)value, length);
151 if (result != ERROR_SUCCESS) throw rdr::SystemException("setBinary", result);
152}
153
154void RegKey::setInt(const TCHAR* valname, int value) const {
155 LONG result = RegSetValueEx(key, valname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
156 if (result != ERROR_SUCCESS) throw rdr::SystemException("setInt", result);
157}
158
159void RegKey::setBool(const TCHAR* valname, bool value) const {
160 setInt(valname, value ? 1 : 0);
161}
162
163TCHAR* RegKey::getString(const TCHAR* valname) const {return getRepresentation(valname);}
164TCHAR* RegKey::getString(const TCHAR* valname, const TCHAR* def) const {
165 try {
166 return getString(valname);
167 } catch(rdr::Exception) {
168 return tstrDup(def);
169 }
170}
171
172void RegKey::getBinary(const TCHAR* valname, void** data, int* length) const {
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000173 TCharArray hex(getRepresentation(valname));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000174 if (!rdr::HexInStream::hexStrToBin(CStr(hex.buf), (char**)data, length))
175 throw rdr::Exception("getBinary failed");
176}
177void RegKey::getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflen) const {
178 try {
179 getBinary(valname, data, length);
180 } catch(rdr::Exception) {
181 if (deflen) {
182 *data = new char[deflen];
183 memcpy(*data, def, deflen);
184 } else
185 *data = 0;
186 *length = deflen;
187 }
188}
189
190int RegKey::getInt(const TCHAR* valname) const {
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000191 TCharArray tmp(getRepresentation(valname));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000192 return _ttoi(tmp.buf);
193}
194int RegKey::getInt(const TCHAR* valname, int def) const {
195 try {
196 return getInt(valname);
197 } catch(rdr::Exception) {
198 return def;
199 }
200}
201
202bool RegKey::getBool(const TCHAR* valname) const {
203 return getInt(valname) > 0;
204}
205bool RegKey::getBool(const TCHAR* valname, bool def) const {
206 return getInt(valname, def ? 1 : 0) > 0;
207}
208
209static inline TCHAR* terminateData(char* data, int length)
210{
211 // We must terminate the string, just to be sure. Stupid Win32...
212 int len = length/sizeof(TCHAR);
213 TCharArray str(len+1);
214 memcpy(str.buf, data, length);
215 str.buf[len] = 0;
216 return str.takeBuf();
217}
218
219TCHAR* RegKey::getRepresentation(const TCHAR* valname) const {
220 DWORD type, length;
221 LONG result = RegQueryValueEx(key, valname, 0, &type, 0, &length);
222 if (result != ERROR_SUCCESS)
223 throw rdr::SystemException("get registry value length", result);
224 CharArray data(length);
225 result = RegQueryValueEx(key, valname, 0, &type, (BYTE*)data.buf, &length);
226 if (result != ERROR_SUCCESS)
227 throw rdr::SystemException("get registry value", result);
228
229 switch (type) {
230 case REG_BINARY:
231 {
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000232 TCharArray hex(rdr::HexOutStream::binToHexStr(data.buf, length));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000233 return hex.takeBuf();
234 }
235 case REG_SZ:
236 if (length) {
237 return terminateData(data.buf, length);
238 } else {
239 return tstrDup(_T(""));
240 }
241 case REG_DWORD:
242 {
243 TCharArray tmp(16);
Peter Åstrand66a2a932010-02-10 10:03:27 +0000244 _stprintf(tmp.buf, _T("%lu"), *((DWORD*)data.buf));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000245 return tmp.takeBuf();
246 }
247 case REG_EXPAND_SZ:
248 {
249 if (length) {
250 TCharArray str(terminateData(data.buf, length));
251 DWORD required = ExpandEnvironmentStrings(str.buf, 0, 0);
252 if (required==0)
253 throw rdr::SystemException("ExpandEnvironmentStrings", GetLastError());
254 TCharArray result(required);
255 length = ExpandEnvironmentStrings(str.buf, result.buf, required);
256 if (required<length)
257 rdr::Exception("unable to expand environment strings");
258 return result.takeBuf();
259 } else {
260 return tstrDup(_T(""));
261 }
262 }
263 default:
264 throw rdr::Exception("unsupported registry type");
265 }
266}
267
268bool RegKey::isValue(const TCHAR* valname) const {
269 try {
Peter Åstrandb22dbef2008-12-09 14:57:53 +0000270 TCharArray tmp(getRepresentation(valname));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000271 return true;
272 } catch(rdr::Exception) {
273 return false;
274 }
275}
276
277const TCHAR* RegKey::getValueName(int i) {
278 DWORD maxValueNameLen;
279 LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0);
280 if (result != ERROR_SUCCESS)
281 throw rdr::SystemException("RegQueryInfoKey", result);
282 if (valueNameBufLen < maxValueNameLen + 1) {
283 valueNameBufLen = maxValueNameLen + 1;
284 delete [] valueName.buf;
285 valueName.buf = new TCHAR[valueNameBufLen];
286 }
287 DWORD length = valueNameBufLen;
288 result = RegEnumValue(key, i, valueName.buf, &length, NULL, 0, 0, 0);
289 if (result == ERROR_NO_MORE_ITEMS) return 0;
290 if (result != ERROR_SUCCESS)
291 throw rdr::SystemException("RegEnumValue", result);
292 return valueName.buf;
293}
294
295const TCHAR* RegKey::getKeyName(int i) {
296 DWORD maxValueNameLen;
297 LONG result = RegQueryInfoKey(key, 0, 0, 0, 0, &maxValueNameLen, 0, 0, 0, 0, 0, 0);
298 if (result != ERROR_SUCCESS)
299 throw rdr::SystemException("RegQueryInfoKey", result);
300 if (valueNameBufLen < maxValueNameLen + 1) {
301 valueNameBufLen = maxValueNameLen + 1;
302 delete [] valueName.buf;
303 valueName.buf = new TCHAR[valueNameBufLen];
304 }
305 DWORD length = valueNameBufLen;
306 result = RegEnumKeyEx(key, i, valueName.buf, &length, NULL, 0, 0, 0);
307 if (result == ERROR_NO_MORE_ITEMS) return 0;
308 if (result != ERROR_SUCCESS)
309 throw rdr::SystemException("RegEnumKey", result);
310 return valueName.buf;
311}