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