/*
* Copyright Likewise Software 2004-2009
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library 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 Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* export.c
*
* Abstract:
*
* Registry
*
* Registry export utilities (export to a win32 compatible registry file)
*
* Authors: Wei Fu (wfu@likewise.com)
* Adam Bernstein (abernstein@likewise.com)
*
*/
#include "rsutils.h"
#include <../parse/includes.h>
#include
#include
static
DWORD
ProcessSubKeys(
HANDLE hReg,
FILE* fp,
HKEY hKey,
DWORD dwNumSubKeys,
DWORD dwMaxSubKeyLen
);
DWORD RegExportBinaryTypeToString(
REG_DATA_TYPE token,
PSTR tokenStr,
BOOLEAN dumpFormat)
{
DWORD dwError = 0;
static char *typeStrs[][2] = {
{ "hex(0):", "REG_NONE" },
{ "REG_SZ", "REG_SZ"},
{ "hex(2):", "REG_EXPAND_SZ" },
{ "hex:", "REG_BINARY" },
{ "dword:", "REG_DWORD" },
{ "dwordbe:", "REG_DWORD_BIG_ENDIAN" },
{ "link:", "REG_LINK" },
{ "hex(7):", "REG_MULTI_SZ" },
{ "hex(8):", "REG_RESOURCE_LIST" },
{ "hex(9):", "REG_FULL_RESOURCE_DESCRIPTOR" },
{ "hex(a):", "REG_RESOURCE_REQUIREMENTS_LIST" },
{ "hex(b):", "REG_QUADWORD" },
{ "unknown12:", "REG_UNKNOWN12" },
{ "unknown13:", "REG_UNKNOWN13" },
{ "unknown14:", "REG_UNKNOWN14" },
{ "unknown15:", "REG_UNKNOWN15" },
{ "unknown16:", "REG_UNKNOWN16" },
{ "unknown17:", "REG_UNKNOWN17" },
{ "unknown18:", "REG_UNKNOWN18" },
{ "unknown19:", "REG_UNKNOWN19" },
{ "unknown20:", "REG_UNKNOWN20" },
{ "REG_KEY", "REG_KEY" },
{ "REG_KEY_DEFAULT", "REG_KEY_DEFAULT" },
{ "REG_PLAIN_TEXT", "REG_PLAIN_TEXT" },
{ "REG_UNKNOWN", "REG_UNKNOWN" },
{ "sza:", "REG_STRING_ARRAY" }, /* Maps to REG_MULTI_SZ */
};
BAIL_ON_INVALID_POINTER(tokenStr);
if (token < ((sizeof(typeStrs)/sizeof(char *))/2))
{
if (dumpFormat)
{
strcpy(tokenStr, typeStrs[token][0]);
}
else
{
strcpy(tokenStr, typeStrs[token][1]);
}
}
else
{
sprintf(tokenStr, "ERROR: No Such Token %d", token);
}
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegExportEntry(
PSTR keyName,
REG_DATA_TYPE valueType,
PSTR valueName,
REG_DATA_TYPE type,
LW_PVOID value,
DWORD valueLen,
PSTR *dumpString,
PDWORD dumpStringLen)
{
DWORD dwError = 0;
switch (type)
{
case REG_BINARY:
case REG_NONE:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
case REG_RESOURCE_LIST:
case REG_FULL_RESOURCE_DESCRIPTOR:
case REG_RESOURCE_REQUIREMENTS_LIST:
case REG_QWORD:
dwError = RegExportBinaryData(valueType,
valueName,
type,
value,
valueLen,
dumpString,
dumpStringLen);
break;
case REG_DWORD:
dwError = RegExportDword(valueType,
valueName,
*((PDWORD) value),
dumpString,
dumpStringLen);
break;
case REG_KEY:
dwError = RegExportRegKey(keyName,
dumpString,
dumpStringLen);
break;
case REG_SZ:
dwError = RegExportString(valueType,
valueName,
value,
dumpString,
dumpStringLen);
break;
case REG_PLAIN_TEXT:
default:
dwError = RegExportPlainText((PCHAR) value,
dumpString,
dumpStringLen);
}
return dwError;
}
DWORD
RegExportDword(
REG_DATA_TYPE valueType,
PSTR valueName,
DWORD value,
PSTR *dumpString,
PDWORD dumpStringLen)
{
DWORD bufLen = 0;
PSTR dumpBuf = NULL;
DWORD dwError = 0;
BAIL_ON_INVALID_POINTER(valueName);
BAIL_ON_INVALID_POINTER(dumpString);
BAIL_ON_INVALID_POINTER(dumpStringLen);
/*
* "name"=1234ABCD\r\n\0
* 14: * ""=1234ABCD\r\n\0
*/
bufLen = strlen(valueName) + 20;
dwError = RegAllocateMemory(sizeof(*dumpBuf) * bufLen, (PVOID*)&dumpBuf);
BAIL_ON_REG_ERROR(dwError);
if (valueType == REG_KEY_DEFAULT)
{
*dumpStringLen = sprintf(dumpBuf, "@=dword:%08x",
value);
}
else
{
*dumpStringLen = sprintf(dumpBuf, "\"%s\"=dword:%08x",
valueName,
value);
}
*dumpString = dumpBuf;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegExportRegKey(
PSTR keyName,
PSTR *dumpString,
PDWORD dumpStringLen)
{
DWORD bufLen = 0;
PSTR dumpBuf = NULL;
DWORD dwError = 0;
BAIL_ON_INVALID_POINTER(keyName);
BAIL_ON_INVALID_POINTER(dumpString);
BAIL_ON_INVALID_POINTER(dumpStringLen);
/*
* [key_name]\r\n\0
* 5: []\r\n\0
*/
bufLen = strlen(keyName) + 5;
dwError = RegAllocateMemory(sizeof(*dumpBuf) * bufLen, (PVOID*)&dumpBuf);
BAIL_ON_REG_ERROR(dwError);
*dumpStringLen = sprintf(dumpBuf, "[%s]", keyName);
*dumpString = dumpBuf;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD RegExportString(
REG_DATA_TYPE valueType,
PSTR valueName,
PSTR value,
PSTR *dumpString,
PDWORD retDumpStringLen)
{
DWORD bufLen = 0;
PSTR dumpBuf = NULL;
PSTR valueEscName = NULL;
DWORD dwError = 0;
DWORD dumpStringLen = 0;
DWORD dwEscapeStringLen = 0;
BAIL_ON_INVALID_POINTER(valueName);
BAIL_ON_INVALID_POINTER(dumpString);
BAIL_ON_INVALID_POINTER(retDumpStringLen);
/*
*/
dwError = RegShellUtilEscapeString(
value,
&valueEscName,
&dwEscapeStringLen);
BAIL_ON_REG_ERROR(dwError);
bufLen = strlen(valueName) + dwEscapeStringLen + 8;
dwError = RegAllocateMemory(sizeof(*dumpBuf) * bufLen, (PVOID*)&dumpBuf);
BAIL_ON_REG_ERROR(dwError);
if (valueType == REG_KEY_DEFAULT)
{
dumpStringLen = sprintf(dumpBuf, "@=\"%s\"",
valueEscName);
}
else
{
dumpStringLen = sprintf(dumpBuf, "\"%s\"=\"%s\"",
valueName,
valueEscName);
}
LWREG_SAFE_FREE_MEMORY(valueEscName);
*retDumpStringLen = dumpStringLen;
*dumpString = dumpBuf;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegExportPlainText(
PCHAR value,
PSTR *dumpString,
PDWORD dumpStringLen)
{
DWORD bufLen = 0;
PSTR dumpBuf = NULL;
DWORD dwError = 0;
BAIL_ON_INVALID_POINTER(dumpString);
BAIL_ON_INVALID_POINTER(dumpStringLen);
bufLen = strlen(value) + 8;
dwError = RegAllocateMemory(sizeof(*dumpBuf) * bufLen, (PVOID*)&dumpBuf);
BAIL_ON_REG_ERROR(dwError);
*dumpStringLen = sprintf(dumpBuf, "%s", (PCHAR) value);
*dumpString = dumpBuf;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegExportBinaryData(
REG_DATA_TYPE valueType,
PSTR valueName,
REG_DATA_TYPE type,
UCHAR *value,
DWORD valueLen,
PSTR *dumpString,
PDWORD dumpStringLen)
{
DWORD bufLen = 0;
DWORD formatLines = 0;
DWORD indx = 0;
DWORD dwError = 0;
DWORD linePos = 0;
PSTR dumpBuf = NULL;
PSTR fmtCursor = NULL;
UCHAR *pValue = NULL;
BOOLEAN firstHex = FALSE;
CHAR typeName[128];
RegExportBinaryTypeToString(type, typeName, TRUE);
/* 5 extra for " "= \\n characters on first line */
bufLen = strlen(valueName) + strlen(typeName) + 6;
/* 4 extra characters per line: Prefix " " spaces, suffix \ and \r\n */
formatLines = valueLen / 25 + 1;
bufLen += valueLen * 3 + (formatLines * 5) + 1;
dwError = RegAllocateMemory(sizeof(*dumpBuf) * bufLen, (PVOID*)&dumpBuf);
BAIL_ON_REG_ERROR(dwError);
/* Format binary prefix */
fmtCursor = dumpBuf;
if (valueType == REG_KEY_DEFAULT)
{
fmtCursor += sprintf(fmtCursor, "@=%s", typeName);
}
else
{
fmtCursor += sprintf(fmtCursor, "\"%s\"=%s",
valueName, typeName);
}
pValue = (UCHAR *) value;
linePos = fmtCursor - dumpBuf;
indx = 0;
while (indx < valueLen)
{
while(((linePos + 3) 0 && dumpString)
{
switch (type)
{
case REG_KEY:
fprintf(fp, "\r\n%.*s\r\n", dumpStringLen, dumpString);
break;
case REG_PLAIN_TEXT:
if (*pPrevType && *pPrevType != type)
{
printf("\n");
}
fprintf(fp, "%*s ", dwValueLen, (PCHAR) value);
break;
default:
fprintf(fp, "%.*s\r\n", dumpStringLen, dumpString);
break;
}
}
fflush(stdout);
*pPrevType = type;
if (dumpString)
{
RegMemoryFree(dumpString);
dumpString = NULL;
}
return 0;
}
static
DWORD
ProcessExportedKeyInfo(
IN HANDLE hReg,
IN FILE* fp,
IN HKEY hKey,
IN PSTR pszKeyName,
IN OUT PREG_DATA_TYPE pPrevType
)
{
DWORD dwError = 0;
DWORD dwValueNameLen = MAX_KEY_LENGTH;
CHAR valueName[MAX_KEY_LENGTH]; // buffer for subkey name
REG_DATA_TYPE dataType = REG_UNKNOWN;
BYTE value[MAX_VALUE_LENGTH] = {0};
DWORD dwValueLen = 0;
int iCount = 0;
DWORD dwValuesCount = 0;
dwError = PrintToRegFile(
fp,
pszKeyName,
REG_KEY,
NULL,
REG_KEY,
NULL,
0,
pPrevType);
BAIL_ON_REG_ERROR(dwError);
dwError = RegQueryInfoKeyA(
hReg,
hKey,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&dwValuesCount,
NULL,
NULL,
NULL,
NULL);
BAIL_ON_REG_ERROR(dwError);
if (!dwValuesCount)
{
goto cleanup;
}
for (iCount = 0; iCount < dwValuesCount; iCount++)
{
memset(valueName, 0, MAX_KEY_LENGTH);
dwValueNameLen = MAX_KEY_LENGTH;
memset(value, 0, MAX_VALUE_LENGTH);
dwValueLen = MAX_VALUE_LENGTH;
dwError = RegEnumValueA((HANDLE)hReg,
hKey,
iCount,
valueName,
&dwValueNameLen,
NULL,
&dataType,
value,
&dwValueLen);
BAIL_ON_REG_ERROR(dwError);
dwError = PrintToRegFile(
fp,
pszKeyName,
dataType,
valueName,
dataType,
value,
dwValueLen,
pPrevType);
BAIL_ON_REG_ERROR(dwError);
}
cleanup:
memset(valueName, 0 , MAX_KEY_LENGTH);
memset(value, 0 , MAX_KEY_LENGTH);
return dwError;
error:
goto cleanup;
}
static
DWORD
ProcessSubKeys(
HANDLE hReg,
FILE* fp,
HKEY hKey,
DWORD dwNumSubKeys,
DWORD dwMaxSubKeyLen
)
{
DWORD dwError = 0;
int iCount = 0;
DWORD dwSubKeyLen = dwMaxSubKeyLen+1;
PWSTR subKey = NULL; // buffer for subkey name
PSTR pszSubKey = NULL;
HKEY hSubKey = NULL;
DWORD dwNumSubSubKeys = 0;
DWORD dwMaxSubSubKeyLen = 0;
CHAR c = '\\';
//Do not free
PSTR pszSubKeyName = NULL;
PWSTR pSubKey = NULL;
// Get the subkeys and values under this key from registry
for (iCount = 0; iCount < dwNumSubKeys; iCount++)
{
dwSubKeyLen = dwMaxSubKeyLen+1;
dwError = RegAllocateMemory(sizeof(*subKey) * dwSubKeyLen, (PVOID*)&subKey);
BAIL_ON_REG_ERROR(dwError);
dwError = RegEnumKeyExW((HANDLE)hReg,
hKey,
iCount,
subKey,
&dwSubKeyLen,
NULL,
NULL,
NULL,
NULL);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringAllocateFromWC16String(&pszSubKey, subKey);
BAIL_ON_REG_ERROR(dwError);
LWREG_SAFE_FREE_MEMORY(subKey);
subKey = NULL;
pszSubKeyName = strrchr(pszSubKey, c);
if (!pszSubKeyName || LW_IS_NULL_OR_EMPTY_STR(pszSubKeyName+1))
{
continue;
}
//Open the subkey
dwError = LwRtlWC16StringAllocateFromCString(&pSubKey,
pszSubKeyName+1);
BAIL_ON_REG_ERROR(dwError);
dwError = RegOpenKeyExW(
hReg,
hKey,
pSubKey,
0,
KEY_READ,
&hSubKey);
BAIL_ON_REG_ERROR(dwError);
dwError = RegQueryInfoKeyA(
(HANDLE) hReg,
hSubKey,
NULL,
NULL,
NULL,
&dwNumSubSubKeys,
&dwMaxSubSubKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
BAIL_ON_REG_ERROR(dwError);
dwError = RegShellUtilExport(
hReg,
fp,
hSubKey,
pszSubKey,
dwNumSubSubKeys,
dwMaxSubSubKeyLen);
BAIL_ON_REG_ERROR(dwError);
if (hSubKey)
{
dwError = RegCloseKey((HANDLE) hReg,
hSubKey);
BAIL_ON_REG_ERROR(dwError);
hSubKey = NULL;
}
LWREG_SAFE_FREE_STRING(pszSubKey);
dwNumSubSubKeys = 0;
dwMaxSubSubKeyLen = 0;
LWREG_SAFE_FREE_MEMORY(pSubKey);
}
cleanup:
if (hSubKey)
{
RegCloseKey((HANDLE) hReg, hSubKey);
hSubKey = NULL;
}
LWREG_SAFE_FREE_STRING(pszSubKey);
LWREG_SAFE_FREE_MEMORY(subKey);
dwNumSubKeys = 0;
LWREG_SAFE_FREE_MEMORY(pSubKey);
return dwError;
error:
goto cleanup;
}
static
DWORD
ProcessRootKeys(
HANDLE hReg,
FILE* fp
)
{
DWORD dwError = 0;
PSTR* ppszRootKeyNames = NULL;
DWORD dwNumRootKeys = 0;
DWORD iCount = 0;
HKEY hRootKey = NULL;
DWORD dwNumSubKeys = 0;
DWORD dwMaxSubKeyLen = 0;
dwError = RegEnumRootKeysA(hReg,
&ppszRootKeyNames,
&dwNumRootKeys);
BAIL_ON_REG_ERROR(dwError);
if (!dwNumRootKeys)
{
goto cleanup;
}
for (iCount = 0; iCount < dwNumRootKeys; iCount++)
{
dwError = RegOpenKeyExA((HANDLE) hReg,
NULL,
ppszRootKeyNames[iCount],
0,
KEY_READ,
&hRootKey);
BAIL_ON_REG_ERROR(dwError);
dwError = RegQueryInfoKeyA(
(HANDLE) hReg,
hRootKey,
NULL,
NULL,
NULL,
&dwNumSubKeys,
&dwMaxSubKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
BAIL_ON_REG_ERROR(dwError);
dwError = RegShellUtilExport(hReg,
fp,
hRootKey,
ppszRootKeyNames[iCount],
dwNumSubKeys,
dwMaxSubKeyLen);
BAIL_ON_REG_ERROR(dwError);
if (hRootKey)
{
dwError = RegCloseKey((HANDLE) hReg,
hRootKey);
BAIL_ON_REG_ERROR(dwError);
hRootKey = NULL;
}
dwNumSubKeys = 0;
dwMaxSubKeyLen = 0;
}
cleanup:
RegFreeStringArray(ppszRootKeyNames, dwNumRootKeys);
if (hRootKey)
{
RegCloseKey((HANDLE) hReg, hRootKey);
}
return dwError;
error:
goto cleanup;
}
DWORD
RegShellUtilExport(
HANDLE hReg,
FILE* fp,
HKEY hKey,
PSTR pszKeyName,
DWORD dwNumSubKeys,
DWORD dwMaxSubKeyLen
)
{
DWORD dwError = 0;
REG_DATA_TYPE prevType = REG_UNKNOWN;
if (hKey)
{
dwError = ProcessExportedKeyInfo(hReg,
fp,
hKey,
pszKeyName,
&prevType);
BAIL_ON_REG_ERROR(dwError);
}
if (hKey && dwNumSubKeys != 0)
{
dwError = ProcessSubKeys(hReg,
fp,
hKey,
dwNumSubKeys,
dwMaxSubKeyLen);
BAIL_ON_REG_ERROR(dwError);
}
else if (hKey == NULL && dwNumSubKeys == 0)
{
dwError = ProcessRootKeys(hReg,
fp);
BAIL_ON_REG_ERROR(dwError);
}
else if (hKey == NULL && dwNumSubKeys != 0)
{
dwError = ERROR_INTERNAL_ERROR;
BAIL_ON_REG_ERROR(dwError);
}
cleanup:
return dwError;
error:
goto cleanup;
}