/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * * This 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 software 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 software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // -=- Registry.cxx #include #include #include #include #include #include #include // These flags are required to control access control inheritance, // but are not defined by VC6's headers. These definitions comes // from the Microsoft Platform SDK. #ifndef PROTECTED_DACL_SECURITY_INFORMATION #define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) #endif #ifndef UNPROTECTED_DACL_SECURITY_INFORMATION #define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) #endif using namespace rfb; using namespace rfb::win32; static LogWriter vlog("Registry"); RegKey::RegKey() : key(0), freeKey(false), valueNameBufLen(0) {} RegKey::RegKey(const HKEY k) : key(0), freeKey(false), valueNameBufLen(0) { LONG result = RegOpenKeyEx(k, 0, 0, KEY_ALL_ACCESS, &key); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegOpenKeyEx(HKEY)", result); vlog.debug("duplicated %p to %p", k, key); freeKey = true; } RegKey::RegKey(const RegKey& k) : key(0), freeKey(false), valueNameBufLen(0) { LONG result = RegOpenKeyEx(k.key, 0, 0, KEY_ALL_ACCESS, &key); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegOpenKeyEx(RegKey&)", result); vlog.debug("duplicated %p to %p", k.key, key); freeKey = true; } RegKey::~RegKey() { close(); } void RegKey::setHKEY(HKEY k, bool fK) { vlog.debug("setHKEY(%p,%d)", k, (int)fK); close(); freeKey = fK; key = k; } bool RegKey::createKey(const RegKey& root, const TCHAR* name) { close(); LONG result = RegCreateKey(root.key, name, &key); if (result != ERROR_SUCCESS) { vlog.error("RegCreateKey(%p, %s): %lx", root.key, name, result); throw rdr::SystemException("RegCreateKeyEx", result); } vlog.debug("createKey(%p,%s) = %p", root.key, (const char*)CStr(name), key); freeKey = true; return true; } void RegKey::openKey(const RegKey& root, const TCHAR* name, bool readOnly) { close(); LONG result = RegOpenKeyEx(root.key, name, 0, readOnly ? KEY_READ : KEY_ALL_ACCESS, &key); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegOpenKeyEx (open)", result); vlog.debug("openKey(%p,%s,%s) = %p", root.key, (const char*)CStr(name), readOnly ? "ro" : "rw", key); freeKey = true; } void RegKey::setDACL(const PACL acl, bool inherit) { DWORD result; if ((result = SetSecurityInfo(key, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION | (inherit ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION), 0, 0, acl, 0)) != ERROR_SUCCESS) throw rdr::SystemException("RegKey::setDACL failed", result); } void RegKey::close() { if (freeKey) { vlog.debug("RegCloseKey(%p)", key); RegCloseKey(key); key = 0; } } void RegKey::deleteKey(const TCHAR* name) const { LONG result = RegDeleteKey(key, name); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegDeleteKey", result); } void RegKey::deleteValue(const TCHAR* name) const { LONG result = RegDeleteValue(key, name); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegDeleteValue", result); } void RegKey::awaitChange(bool watchSubTree, DWORD filter, HANDLE event) const { LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, event, event != 0); if (result != ERROR_SUCCESS) throw rdr::SystemException("RegNotifyChangeKeyValue", result); } RegKey::operator HKEY() const {return key;} void RegKey::setExpandString(const TCHAR* valname, const TCHAR* value) const { LONG result = RegSetValueEx(key, valname, 0, REG_EXPAND_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR)); if (result != ERROR_SUCCESS) throw rdr::SystemException("setExpandString", result); } void RegKey::setString(const TCHAR* valname, const TCHAR* value) const { LONG result = RegSetValueEx(key, valname, 0, REG_SZ, (const BYTE*)value, (_tcslen(value)+1)*sizeof(TCHAR)); if (result != ERROR_SUCCESS) throw rdr::SystemException("setString", result); } void RegKey::setBinary(const TCHAR* valname, const void* value, int length) const { LONG result = RegSetValueEx(key, valname, 0, REG_BINARY, (const BYTE*)value, length); if (result != ERROR_SUCCESS) throw rdr::SystemException("setBinary", result); } void RegKey::setInt(const TCHAR* valname, int value) const { LONG result = RegSetValueEx(key, valname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value)); if (result != ERROR_SUCCESS) throw rdr::SystemException("setInt", result); } void RegKey::setBool(const TCHAR* valname, bool value) const { setInt(valname, value ? 1 : 0); } TCHAR* RegKey::getString(const TCHAR* valname) const {return getRepresentation(valname);} TCHAR* RegKey::getString(const TCHAR* valname, const TCHAR* def) const { try { return getString(valname); } catch(rdr::Exception&) { return tstrDup(def); } } void RegKey::getBinary(const TCHAR* valname, void** data, int* length) const { TCharArray hex(getRepresentation(valname)); if (!rdr::HexInStream::hexStrToBin(CStr(hex.buf), (char**)data, length)) throw rdr::Exception("getBinary failed"); } void RegKey::getBinary(const TCHAR* valname, void** data, int* length, void* def, int deflen) const { try { getBinary(valname, data, length); } catch(rdr::Exception&) { if (deflen) { *data = new char[deflen]; memcpy(*data, def, deflen); } else *data = 0; *length = deflen; } } int RegKey::getInt(const TCHAR* valname) const { TCharArray tmp(getRepresentation(valname)); return _ttoi(tmp.buf); } int RegKey::getInt(const TCHAR* valname, int def) const { try { return getInt(valname); } catch(rdr::Exception&) { return def; } } bool RegKey::getBool(const TCHAR* valname) const { return getInt(valname) > 0; } bool RegKey::getBool(const TCHAR* valname, bool def) const { return getInt(valname, def ? 1 : 0) > 0; } static inline TCHAR* terminateData(char* data, int length) { // We must terminate the string, just to be sure. Stupid Win32... int len = length/sizeof(TCHAR); TCharArray str(len+1); memcpy(str.buf, data, length); str.buf[len] = 0; return str.takeBuf(); } TCHAR* RegKey::getRepresentation(const TCHAR* valname) const { DWORD type, length; LONG result = RegQueryValueEx(key, valname, 0, &type, 0, &length); if (result != ERROR_SUCCESS) throw rdr::SystemException("get registry value length", result); CharArray data(length); result = RegQueryValueEx(key, valname, 0, &type, (BYTE*)data.buf, &length); if (result != ERROR_SUCCESS) throw rdr::SystemException("get registry value", result); switch (type) { case REG_BINARY: { TCharArray hex(rdr::HexOutStream::binToHexStr(data.buf, length)); return hex.takeBuf(); } case REG_SZ: if (length) { return terminateData(data.buf, length); } else { return tstrDup(_T("")); } case REG_DWORD: { TCharArray tmp(16); _stprintf(tmp.buf, _T("%lu"), *((DWORD*)data.buf)); return tmp.takeBuf(); } case REG_EXPAND_SZ: { if (length) { TCharArray str(terminateData(data.buf, length)); DWORD required = ExpandEnvironmentStrings(str.buf, 0, 0); if (required==0) throw rdr::SystemException("ExpandEnvironmentStrings", GetLastError()); TCharArray result(required); length = ExpandEnvironmentStrings(str.buf, result.buf, required); if (required