1 /* 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>
23 #include <rdr/MemOutStream.h>
24 #include <rdr/HexOutStream.h>
25 #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
40 using namespace rfb;
41 using namespace rfb::win32;
42
43
44 static LogWriter vlog("Registry");
45
46
RegKey()47 RegKey::RegKey() : key(0), freeKey(false), valueNameBufLen(0) {}
48
RegKey(const HKEY k)49 RegKey::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);
53 vlog.debug("duplicated %p to %p", k, key);
54 freeKey = true;
55 }
56
RegKey(const RegKey & k)57 RegKey::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);
61 vlog.debug("duplicated %p to %p", k.key, key);
62 freeKey = true;
63 }
64
~RegKey()65 RegKey::~RegKey() {
66 close();
67 }
68
69
setHKEY(HKEY k,bool fK)70 void RegKey::setHKEY(HKEY k, bool fK) {
71 vlog.debug("setHKEY(%p,%d)", k, (int)fK);
72 close();
73 freeKey = fK;
74 key = k;
75 }
76
77
createKey(const RegKey & root,const TCHAR * name)78 bool RegKey::createKey(const RegKey& root, const TCHAR* name) {
79 close();
80 LONG result = RegCreateKey(root.key, name, &key);
81 if (result != ERROR_SUCCESS) {
82 vlog.error("RegCreateKey(%p, %s): %lx", root.key, name, result);
83 throw rdr::SystemException("RegCreateKeyEx", result);
84 }
85 vlog.debug("createKey(%p,%s) = %p", root.key, (const char*)CStr(name), key);
86 freeKey = true;
87 return true;
88 }
89
openKey(const RegKey & root,const TCHAR * name,bool readOnly)90 void 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);
95 vlog.debug("openKey(%p,%s,%s) = %p", root.key, (const char*)CStr(name),
96 readOnly ? "ro" : "rw", key);
97 freeKey = true;
98 }
99
setDACL(const PACL acl,bool inherit)100 void RegKey::setDACL(const PACL acl, bool inherit) {
101 DWORD result;
102 if ((result = SetSecurityInfo(key, SE_REGISTRY_KEY,
103 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
close()109 void RegKey::close() {
110 if (freeKey) {
111 vlog.debug("RegCloseKey(%p)", key);
112 RegCloseKey(key);
113 key = 0;
114 }
115 }
116
deleteKey(const TCHAR * name) const117 void 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
deleteValue(const TCHAR * name) const123 void 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
awaitChange(bool watchSubTree,DWORD filter,HANDLE event) const129 void 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
operator HKEY() const136 RegKey::operator HKEY() const {return key;}
137
138
setExpandString(const TCHAR * valname,const TCHAR * value) const139 void 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
setString(const TCHAR * valname,const TCHAR * value) const144 void 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
setBinary(const TCHAR * valname,const void * value,size_t length) const149 void RegKey::setBinary(const TCHAR* valname, const void* value, size_t 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
setInt(const TCHAR * valname,int value) const154 void 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
setBool(const TCHAR * valname,bool value) const159 void RegKey::setBool(const TCHAR* valname, bool value) const {
160 setInt(valname, value ? 1 : 0);
161 }
162
getString(const TCHAR * valname) const163 TCHAR* RegKey::getString(const TCHAR* valname) const {return getRepresentation(valname);}
getString(const TCHAR * valname,const TCHAR * def) const164 TCHAR* 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
getBinary(const TCHAR * valname,void ** data,size_t * length) const172 void RegKey::getBinary(const TCHAR* valname, void** data, size_t* length) const {
173 TCharArray hex(getRepresentation(valname));
174 if (!rdr::HexInStream::hexStrToBin(CStr(hex.buf), (char**)data, length))
175 throw rdr::Exception("getBinary failed");
176 }
getBinary(const TCHAR * valname,void ** data,size_t * length,void * def,size_t deflen) const177 void RegKey::getBinary(const TCHAR* valname, void** data, size_t* length, void* def, size_t 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
getInt(const TCHAR * valname) const190 int RegKey::getInt(const TCHAR* valname) const {
191 TCharArray tmp(getRepresentation(valname));
192 return _ttoi(tmp.buf);
193 }
getInt(const TCHAR * valname,int def) const194 int RegKey::getInt(const TCHAR* valname, int def) const {
195 try {
196 return getInt(valname);
197 } catch(rdr::Exception&) {
198 return def;
199 }
200 }
201
getBool(const TCHAR * valname) const202 bool RegKey::getBool(const TCHAR* valname) const {
203 return getInt(valname) > 0;
204 }
getBool(const TCHAR * valname,bool def) const205 bool RegKey::getBool(const TCHAR* valname, bool def) const {
206 return getInt(valname, def ? 1 : 0) > 0;
207 }
208
terminateData(char * data,int length)209 static 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
getRepresentation(const TCHAR * valname) const219 TCHAR* 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 {
232 TCharArray hex(rdr::HexOutStream::binToHexStr(data.buf, length));
233 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);
244 _stprintf(tmp.buf, _T("%lu"), *((DWORD*)data.buf));
245 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 throw 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
isValue(const TCHAR * valname) const268 bool RegKey::isValue(const TCHAR* valname) const {
269 try {
270 TCharArray tmp(getRepresentation(valname));
271 return true;
272 } catch(rdr::Exception&) {
273 return false;
274 }
275 }
276
getValueName(int i)277 const 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
getKeyName(int i)295 const 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 }
312