/*
* 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:
*
* cmdparse .c
*
* Abstract:
*
* Registry
*
* Registry Shell command-line parser functionalty
*
* Authors: Adam Bernstein (abernstein@likewise.com)
*/
/*
* regshell (Registry Shell) command grammar
*
* list_keys ["[KeyName]"]
* list_values ["[KeyName]"]
* add_key "[KeyName]"
* cd "[KeyName]"
* delete_key "[KeyName]"
* delete_tree "[KeyName]"
* set_value ["[KeyName]"] "ValueName" "Value" ["Value2"] ["Value3"] [...]
* add_value ["[KeyName]"] "ValueName" type "Value" ["Value2"] ["Value3"] [...]
*
* Note: "KeyName" format is [HKEY_THIS_MACHINE/Subkey1/SubKey2]. ["[KeyName]"]
* means the key parameter is optional.
*
* Token sequence from reglex for above comands:
* list_keys: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* list_values: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* add_key: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* add_value: REGLEX_PLAIN_TEXT [REGLEX_REG_KEY]
* REGLEX_REG_SZ|REGLEX_PLAIN_TEXT REGLEX_PLAIN_TEXT
* REGLEX_REG_SZ ...
* cd: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* delete_key: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* delete_tree: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* set_value: REGLEX_PLAIN_TEXT REGLEX_REG_KEY
* REGLEX_REG_SZ|REGLEX_PLAIN_TEXT
* REGLEX_PLAIN_TEXT REGLEX_REG_SZ ...
*
* Supported types:
* REG_SZ
* REG_DWORD
* REG_MULTISZ
* REG_BINARY
*
*
* BNF Grammar for Registry Shell
*
* ::=
* | |
*
*
*
* ::= "list_keys" | "list_values" | "add_key" |
* "add_value" | "cd" | "delete_key" |
* "delete_tree" | "set_value"
*
* ::= "[" "]"
* ::=
*
* ::=
*
* ::=
* ::= [a-zA-Z0-9\\/_-{}\*\| \$+=#<>~&®]
* ::= "\r\n" | "\r"
*
* ::= REG_SZ | REG_DWORD | REG_MULTISZ | REG_BINARY
*
* ::=
* ::= "'" "'"
* ::=
* ::= UCS2-CHAR | UTF-8-CHAR
*/
#if 0
#define _LW_DEBUG
#endif
#include "regshell.h"
typedef enum _REGSHELL_HEXSTRING_STATE_E
{
REGSHELL_HEX_START,
REGSHELL_HEX_LEADING_SPACE,
REGSHELL_HEX_HEXDIGIT,
REGSHELL_HEX_SPACE_SEPARATOR,
REGSHELL_HEX_COMMA_SEPARATOR,
REGSHELL_HEX_END,
REGSHELL_HEX_ERROR,
REGSHELL_HEX_STOP,
} REGSHELL_HEXSTRING_STATE_E;
typedef enum _REGSHELL_CMDLINE_STATE_E
{
REGSHELL_CMDLINE_STATE_FIRST = 0,
REGSHELL_CMDLINE_STATE_VERB,
REGSHELL_CMDLINE_STATE_LIST_KEYS,
REGSHELL_CMDLINE_STATE_LIST_KEYS_REGKEY,
REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP,
REGSHELL_CMDLINE_STATE_CD,
REGSHELL_CMDLINE_STATE_CD_REGKEY,
REGSHELL_CMDLINE_STATE_CD_STOP,
REGSHELL_CMDLINE_STATE_ADDKEY,
REGSHELL_CMDLINE_STATE_ADDKEY_REGKEY,
REGSHELL_CMDLINE_STATE_ADDKEY_STOP,
REGSHELL_CMDLINE_STATE_ADDVALUE,
REGSHELL_CMDLINE_STATE_ADDVALUE_KEYNAME,
REGSHELL_CMDLINE_STATE_ADDVALUE_VALUENAME,
REGSHELL_CMDLINE_STATE_ADDVALUE_TYPE,
REGSHELL_CMDLINE_STATE_ADDVALUE_VALUE,
REGSHELL_CMDLINE_STATE_ADDVALUE_STOP,
REGSHELL_CMDLINE_STATE_IMPORT,
REGSHELL_CMDLINE_STATE_IMPORT_FILE,
REGSHELL_CMDLINE_STATE_IMPORT_STOP,
} REGSHELL_CMDLINE_STATE_E, *PREGSHELL_CMDLINE_STATE_E;
static REGSHELL_CMD_ID shellCmds[] = {
{ "", REGSHELL_CMD_NONE },
{ "list_keys", REGSHELL_CMD_LIST_KEYS },
{ "dir", REGSHELL_CMD_DIRECTORY },
{ "ls", REGSHELL_CMD_LIST },
{ "list_values", REGSHELL_CMD_LIST_VALUES },
{ "add_key", REGSHELL_CMD_ADD_KEY },
{ "add_value", REGSHELL_CMD_ADD_VALUE },
{ "cd", REGSHELL_CMD_CHDIR },
{ "delete_key", REGSHELL_CMD_DELETE_KEY },
{ "delete_value", REGSHELL_CMD_DELETE_VALUE },
{ "delete_tree", REGSHELL_CMD_DELETE_TREE },
{ "set_value", REGSHELL_CMD_SET_VALUE },
{ "set_hive", REGSHELL_CMD_SET_HIVE },
{ "pwd", REGSHELL_CMD_PWD },
{ "help", REGSHELL_CMD_HELP },
{ "exit", REGSHELL_CMD_QUIT },
{ "quit", REGSHELL_CMD_QUIT },
{ "import", REGSHELL_CMD_IMPORT },
{ "export", REGSHELL_CMD_EXPORT },
{ "upgrade", REGSHELL_CMD_UPGRADE },
};
DWORD
RegShellCmdEnumToString(
REGSHELL_CMD_E cmdEnum,
PCHAR cmdString)
{
DWORD dwError = 0;
if (cmdEnumcommand = cmd;
*pCmdItem = pNewCmdItem;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegShellCmdParseFree(
PREGSHELL_CMD_ITEM pCmdItem)
{
DWORD dwError = 0;
DWORD i = 0;
BAIL_ON_INVALID_POINTER(pCmdItem);
LWREG_SAFE_FREE_MEMORY(pCmdItem->keyName);
LWREG_SAFE_FREE_MEMORY(pCmdItem->valueName);
LWREG_SAFE_FREE_MEMORY(pCmdItem->binaryValue);
for (i=0; iargsCount; i++)
{
LWREG_SAFE_FREE_MEMORY(pCmdItem->args[i]);
}
LWREG_SAFE_FREE_MEMORY(pCmdItem->args);
LWREG_SAFE_FREE_MEMORY(pCmdItem);
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegShellCmdParseKeyName(
PREGSHELL_PARSE_STATE pParseState,
REGSHELL_CMD_E cmd,
PSTR pszKeyName,
PREGSHELL_CMD_ITEM *pRetCmdItem)
{
DWORD dwError = 0;
DWORD dwRootKeyError = LWREG_ERROR_NO_SUCH_KEY_OR_VALUE;
DWORD keyNameLen = 0;
DWORD dwOffset = 0;
PSTR pszBackslash = NULL;
PSTR pszRootKey = NULL;
PSTR pszTmpKeyName = NULL;
PSTR pszSubKey = NULL;
PREGSHELL_CMD_ITEM pCmdItem = NULL;
HKEY hRootKey = NULL;
DWORD dwKeyLen = 0;
if (pszKeyName[0] == '[')
{
dwOffset++;
}
dwError = RegCStringDuplicate(&pszRootKey, &pszKeyName[dwOffset]);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(&pszTmpKeyName, &pszKeyName[dwOffset]);
BAIL_ON_REG_ERROR(dwError);
dwKeyLen = strlen(pszTmpKeyName);
/* Nuke out trailing \ and ] from keyname */
if (dwKeyLen > 0 && pszTmpKeyName[dwKeyLen-1] == ']')
{
pszTmpKeyName[dwKeyLen-1] = '\0';
dwKeyLen--;
}
pszBackslash = strchr(pszRootKey, '\\');
if (pszBackslash)
{
*pszBackslash = '\0';
dwRootKeyError = RegOpenKeyExA(
pParseState->hReg,
NULL,
pszRootKey,
0,
KEY_READ,
&hRootKey);
if (dwRootKeyError == 0)
{
RegCloseKey(pParseState->hReg, hRootKey);
pszSubKey = &pszTmpKeyName[strlen(pszRootKey)];
pParseState->pszFullRootKeyName = pszRootKey;
pszRootKey = NULL;
}
else {
pszSubKey = pszTmpKeyName;
}
}
else
{
pszSubKey = pszTmpKeyName;
}
dwKeyLen = strlen(pszSubKey);
if (dwKeyLen > 1 && pszSubKey[dwKeyLen-1] == '\\')
{
pszSubKey[dwKeyLen-1] = '\0';
dwKeyLen--;
}
dwError = RegShellCmdParseCommand(
cmd,
&pCmdItem);
BAIL_ON_REG_ERROR(dwError);
keyNameLen = strlen(pszSubKey);
if (pszSubKey[0] == '[' && pszSubKey[keyNameLen-1] == ']')
{
dwError = RegCStringDuplicate(&pCmdItem->keyName, pszSubKey);
BAIL_ON_REG_ERROR(dwError);
/*
* Copy only the stuff between the [ ] delimiters. The copied string is
* big enough to do this.
*/
strcpy(pCmdItem->keyName, &pszSubKey[1]);
pCmdItem->keyName[keyNameLen - 2] = '\0';
}
else
{
dwError = RegAllocateMemory(sizeof(CHAR)*(keyNameLen + 2), (PVOID*)&pCmdItem->keyName);
BAIL_ON_REG_ERROR(dwError);
strcat(pCmdItem->keyName, pszSubKey);
}
keyNameLen = strlen(pCmdItem->keyName);
if (pCmdItem->keyName[keyNameLen-1] == ']')
{
pCmdItem->keyName[keyNameLen-1] = '\0';
}
if (pCmdItem->keyName[0] == '\0')
{
LWREG_SAFE_FREE_STRING(pCmdItem->keyName);
}
if (pRetCmdItem)
{
*pRetCmdItem = pCmdItem;
}
cleanup:
LWREG_SAFE_FREE_STRING(pszRootKey);
LWREG_SAFE_FREE_STRING(pszTmpKeyName);
return dwError;
error:
goto cleanup;
}
DWORD
RegShellParseStringType(
PCHAR pszType,
PREG_DATA_TYPE pType,
PDWORD pBackendType)
{
DWORD i = 0;
DWORD dwError = 0;
DWORD backendType = 0;
REG_DATA_TYPE type = REG_UNKNOWN;
static REGSHELL_REG_TYPE_ENTRY typeStrs[] = {
{ "REG_DWORD", REG_DWORD, RRF_RT_REG_DWORD },
{ "REG_SZ", REG_SZ, RRF_RT_REG_SZ },
{ "REG_BINARY", REG_BINARY, RRF_RT_REG_BINARY },
{ "REG_NONE", REG_NONE, RRF_RT_REG_NONE },
{ "REG_EXPAND_SZ", REG_EXPAND_SZ, RRF_RT_REG_EXPAND_SZ },
{ "REG_MULTI_SZ", REG_MULTI_SZ, RRF_RT_REG_MULTI_SZ },
{ "REG_RESOURCE_LIST", REG_RESOURCE_LIST, RRF_RT_ANY },
{ "REG_FULL_RESOURCE_DESCRIPTOR",
REG_FULL_RESOURCE_DESCRIPTOR,
RRF_RT_ANY },
{ "REG_RESOURCE_REQUIREMENTS_LIST",
REG_RESOURCE_REQUIREMENTS_LIST ,
RRF_RT_ANY },
{ "REG_QUADWORD", REG_QWORD, RRF_RT_QWORD },
{ "REG_KEY", REG_KEY, RRF_RT_REG_SZ },
{ "REG_KEY_DEFAULT", REG_KEY_DEFAULT, RRF_RT_REG_SZ },
{ "REG_PLAIN_TEXT", REG_PLAIN_TEXT, RRF_RT_REG_SZ },
};
BAIL_ON_INVALID_POINTER(pType);
for (i=0; i 10)
{
dwError = RegMapErrnoToLwRegError(ERANGE);
BAIL_ON_REG_ERROR(dwError);
}
/*
* Explicitly set errno to 0 here. When previous value entered
* was a legitimate overflow (e.g 4294967297), errno is set.
* Now ULONG_MAX (4294967295) is entered. errno is not set, because
* no error occurred, but errno is still the value from the previous
* error, and the legitimate ULONG_MAX value is flagged as an error.
*/
errno = 0;
ulValue = strtoul(pszHexString, &pszEndValue, dwBase);
dwErrno = errno;
if (ulValue == ULONG_MAX && dwErrno == ERANGE)
{
dwError = RegMapErrnoToLwRegError(dwErrno);
BAIL_ON_REG_ERROR(dwError);
}
/* For 64-bit systems, catch overflow for DWORD (UINT32_MAX) */
if (ulValue > LW_MAXDWORD)
{
dwError = RegMapErrnoToLwRegError(ERANGE);
BAIL_ON_REG_ERROR(dwError);
}
dwError = RegAllocateMemory(sizeof(DWORD), (PVOID*)&pdwValue);
BAIL_ON_REG_ERROR(dwError);
*pdwValue = (DWORD) ulValue;
*ppBinaryValue = (PUCHAR) pdwValue;
*pBinaryValueLen = sizeof(DWORD);
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegShellImportBinaryString(
PCHAR pszHexString,
PUCHAR *ppBinaryValue,
PDWORD pBinaryValueLen)
{
DWORD dwError = 0;
CHAR pszHexArray[3];
REGSHELL_HEXSTRING_STATE_E state = REGSHELL_HEX_START;
PCHAR cursor = NULL;
DWORD hexDigitCount = 0;
DWORD hexDigitModCount = 0;
PUCHAR binaryValue = NULL;
DWORD binaryValueLen = 0;
DWORD dwHexStringLen = 0;
BAIL_ON_INVALID_POINTER(pszHexString);
BAIL_ON_INVALID_POINTER(ppBinaryValue);
BAIL_ON_INVALID_POINTER(pBinaryValueLen);
dwError = RegAllocateMemory(sizeof(UCHAR) * (strlen(pszHexString) / 2+1), (PVOID*)&binaryValue);
BAIL_ON_REG_ERROR(dwError);
dwError = RegShellHexStringExtentLen(
pszHexString,
&dwHexStringLen);
BAIL_ON_REG_ERROR(dwError);
if (dwHexStringLen % 2)
{
hexDigitModCount = 1;
}
cursor = pszHexString;
do
{
if (*cursor == '\0')
{
if (hexDigitCount > 0)
{
state = REGSHELL_HEX_END;
}
else
{
break;
}
}
switch (state)
{
case REGSHELL_HEX_START:
if (hexDigitModCount)
{
pszHexArray[0] = '0';
pszHexArray[1] = '\0';
}
hexDigitCount = hexDigitModCount;
hexDigitModCount = 0;
if (*cursor == ' ')
{
state = REGSHELL_HEX_LEADING_SPACE;
}
else if (isxdigit((int)*cursor))
{
state = REGSHELL_HEX_HEXDIGIT;
}
else
{
state = REGSHELL_HEX_ERROR;
}
break;
case REGSHELL_HEX_LEADING_SPACE:
if (*cursor == ' ')
{
cursor++;
}
else if (isxdigit((int)*cursor))
{
state = REGSHELL_HEX_HEXDIGIT;
}
else
{
state = REGSHELL_HEX_ERROR;
}
break;
case REGSHELL_HEX_HEXDIGIT:
if (isxdigit((int)*cursor))
{
pszHexArray[hexDigitCount++] = *cursor++;
pszHexArray[hexDigitCount] = '\0';
if (hexDigitCount == 2 && isxdigit((int)*cursor))
{
state = REGSHELL_HEX_END;
}
}
else if (*cursor == ' ')
{
state = REGSHELL_HEX_SPACE_SEPARATOR;
}
else if (*cursor == ',')
{
state = REGSHELL_HEX_COMMA_SEPARATOR;
cursor++;
}
else if (*cursor == '\n')
{
dwError = RegShellHexStringExtentLen(
cursor,
&dwHexStringLen);
BAIL_ON_REG_ERROR(dwError);
if (dwHexStringLen % 2)
{
hexDigitModCount = 1;
}
state = REGSHELL_HEX_END;
}
else
{
state = REGSHELL_HEX_ERROR;
}
break;
case REGSHELL_HEX_SPACE_SEPARATOR:
if (*cursor == ' ')
{
cursor++;
}
else if (isxdigit((int)*cursor))
{
dwError = RegShellHexStringExtentLen(
cursor,
&dwHexStringLen);
BAIL_ON_REG_ERROR(dwError);
if (dwHexStringLen % 2)
{
hexDigitModCount = 1;
}
state = REGSHELL_HEX_END;
}
else
{
state = REGSHELL_HEX_ERROR;
}
break;
case REGSHELL_HEX_COMMA_SEPARATOR:
if (*cursor == ' ')
{
state = REGSHELL_HEX_SPACE_SEPARATOR;
}
else if (isxdigit((int)*cursor))
{
dwError = RegShellHexStringExtentLen(
cursor,
&dwHexStringLen);
BAIL_ON_REG_ERROR(dwError);
if (dwHexStringLen % 2)
{
hexDigitModCount = 1;
}
state = REGSHELL_HEX_END;
}
else
{
state = REGSHELL_HEX_ERROR;
}
break;
case REGSHELL_HEX_END:
if (hexDigitCount < 2)
{
pszHexArray[1] = pszHexArray[0];
pszHexArray[0] = ' ';
}
binaryValue[binaryValueLen] =
(UCHAR) strtoul(pszHexArray, NULL, 16);
binaryValueLen++;
hexDigitCount = 0;
pszHexArray[hexDigitCount] = '\0';
if (*cursor == '\0' || *cursor == '\n')
{
state = REGSHELL_HEX_STOP;
}
else
{
state = REGSHELL_HEX_START;
}
break;
case REGSHELL_HEX_ERROR:
printf("RegShellImportBinaryString: ERROR: "
"invalid character '%c'\n", *cursor);
state = REGSHELL_HEX_STOP;
dwError = LWREG_ERROR_INVALID_CONTEXT;
BAIL_ON_REG_ERROR(dwError);
break;
case REGSHELL_HEX_STOP:
default:
break;
}
} while (state != REGSHELL_HEX_STOP);
if (binaryValueLen > 0)
{
*ppBinaryValue = binaryValue;
*pBinaryValueLen = binaryValueLen;
}
cleanup:
return dwError;
error:
if (binaryValue)
{
RegMemoryFree(binaryValue);
}
goto cleanup;
}
DWORD
RegShellCmdParseValueName(
PREGSHELL_PARSE_STATE pParseState,
REGSHELL_CMD_E cmd,
DWORD argc,
PCHAR *argv,
PREGSHELL_CMD_ITEM *pRetCmdItem)
{
DWORD dwError = 0;
DWORD argCount = 0;
DWORD i = 0;
DWORD binaryValueLen = 0;
DWORD argIndx = 2;
BOOLEAN bFullPath = FALSE;
PSTR pszValue = NULL;
PSTR pszType = NULL;
PSTR pszString = NULL;
PSTR pszKeyName = NULL;
PUCHAR binaryValue = NULL;
PBYTE multiString = NULL;
ssize_t multiStringLen = 0;
PREGSHELL_CMD_ITEM pCmdItem = NULL;
BAIL_ON_INVALID_POINTER(argv);
BAIL_ON_INVALID_POINTER(pRetCmdItem);
if (argv[2][0] == '[')
{
dwError = RegShellCmdParseKeyName(
pParseState,
cmd,
argv[2],
&pCmdItem);
argIndx = 3;
}
else
{
dwError = RegShellCmdParseCommand(
cmd,
&pCmdItem);
}
pszValue = argv[argIndx++];
/* format: add_value [[subkeyname]] value_name */
if (pCmdItem->command == REGSHELL_CMD_DELETE_VALUE)
{
dwError = RegCStringDuplicate(&pCmdItem->valueName, pszValue);
BAIL_ON_REG_ERROR(dwError);
*pRetCmdItem = pCmdItem;
return 0;
}
if (pCmdItem->command != REGSHELL_CMD_SET_VALUE)
{
pszType = argv[argIndx++];
}
else
{
if (pCmdItem)
{
pszKeyName = pCmdItem->keyName;
if (pszKeyName && pszKeyName[0] == '\\')
{
pszKeyName++;
bFullPath = TRUE;
}
}
dwError = RegShellUtilGetValue(
pParseState->hReg,
RegShellGetRootKey(pParseState),
!bFullPath ? RegShellGetDefaultKey(pParseState) : NULL,
pszKeyName,
pszValue,
&pCmdItem->type,
NULL,
NULL);
BAIL_ON_REG_ERROR(dwError);
}
argCount = argc - argIndx;
if (argCount < 0)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(&pCmdItem->valueName, pszValue);
BAIL_ON_REG_ERROR(dwError);
if (pszType)
{
dwError = RegShellParseStringType(
pszType,
&pCmdItem->type,
&pCmdItem->backendType);
BAIL_ON_REG_ERROR(dwError);
}
switch (pCmdItem->type)
{
case REG_BINARY:
if (argCount == 0)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
break;
case REG_DWORD:
if (argCount != 1)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
break;
case REG_SZ:
if (argCount > 1)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
break;
default:
break;
}
if (argCount > 0)
{
dwError = RegAllocateMemory(sizeof(*pCmdItem->args) * (argCount + 1), (PVOID*)&pCmdItem->args);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->argsCount = argCount;
for (i=0; iargs[i], argv[i+argIndx]);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->args[i+1] = NULL;
BAIL_ON_REG_ERROR(dwError);
}
}
if (pCmdItem->binaryValue)
{
RegMemoryFree(pCmdItem->binaryValue);
pCmdItem->binaryValue = NULL;
}
switch (pCmdItem->type)
{
case REG_DWORD:
dwError = RegShellImportDwordString(
pCmdItem->args[0],
&binaryValue,
&binaryValueLen);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->binaryValue = binaryValue;
pCmdItem->binaryValueLen = sizeof(DWORD);
binaryValue = NULL;
break;
case REG_BINARY:
dwError = RegShellImportBinaryString(
pCmdItem->args[0],
&binaryValue,
&binaryValueLen);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->binaryValue = binaryValue;
pCmdItem->binaryValueLen = binaryValueLen;
binaryValue = NULL;
break;
case REG_SZ:
dwError = RegCStringDuplicate(&pszString, pCmdItem->args[0]);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->binaryValue = (PUCHAR) pszString;
pCmdItem->binaryValueLen = strlen(pszString);
pszString = NULL;
BAIL_ON_REG_ERROR(dwError);
break;
case REG_MULTI_SZ:
dwError = RegMultiStrsToByteArray(pCmdItem->args,
&multiString,
&multiStringLen);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->binaryValue = (PUCHAR) multiString;
pCmdItem->binaryValueLen = multiStringLen;
multiString = NULL;
break;
default:
break;
}
*pRetCmdItem = pCmdItem;
pCmdItem = NULL;
cleanup:
LWREG_SAFE_FREE_STRING(pszString);
LWREG_SAFE_FREE_MEMORY(binaryValue);
LWREG_SAFE_FREE_MEMORY(multiString);
RegShellCmdParseFree(pCmdItem);
return dwError;
error:
goto cleanup;
}
DWORD
RegShellDumpCmdItem(
PREGSHELL_CMD_ITEM rsItem)
{
CHAR tokenName[128];
PSTR pszDumpData = NULL;
DWORD dumpDataLen = 0;
DWORD i;
DWORD dwError = 0;
PSTR *outMultiSz = NULL;
BAIL_ON_INVALID_POINTER(rsItem);
RegShellCmdEnumToString(rsItem->command, tokenName);
printf("DumpCmd: command=%s\n", tokenName);
if (rsItem->keyName)
{
printf("DumpCmd: keyName=%s\n", rsItem->keyName);
}
if (rsItem->valueName)
{
printf("DumpCmd: valueName=%s\n", rsItem->valueName);
}
if (rsItem->type != REG_UNKNOWN)
{
RegExportBinaryTypeToString(
rsItem->type,
tokenName,
FALSE);
printf("DumpCmd: type=%s\n", tokenName);
}
for (i=0; iargsCount; i++)
{
printf("DumpCmd: args[%d]='%s'\n", i, rsItem->args[i]);
}
switch (rsItem->type)
{
case REG_SZ:
printf("DumpCmd: value = '%s'\n", (CHAR *) rsItem->binaryValue);
break;
case REG_DWORD:
printf("DumpCmd: value = '%08x'\n", *(DWORD*) rsItem->binaryValue);
break;
case REG_BINARY:
dwError = RegExportBinaryData(
REG_SZ,
"test_value",
REG_BINARY,
rsItem->binaryValue,
rsItem->binaryValueLen,
&pszDumpData,
&dumpDataLen);
BAIL_ON_REG_ERROR(dwError);
printf("RegShellDumpCmdItem: '%s'\n", pszDumpData);
break;
case REG_MULTI_SZ:
dwError = RegByteArrayToMultiStrs(
rsItem->binaryValue,
rsItem->binaryValueLen,
&outMultiSz);
BAIL_ON_REG_ERROR(dwError);
for (i=0; outMultiSz[i]; i++)
{
printf("DumpCmd: outMultiSz[%d] = '%s'\n",
i, outMultiSz[i]);
}
default:
break;
}
cleanup:
if (outMultiSz)
{
for (i=0; outMultiSz[i]; i++)
{
LWREG_SAFE_FREE_STRING(outMultiSz[i]);
}
LWREG_SAFE_FREE_MEMORY(outMultiSz);
}
LWREG_SAFE_FREE_STRING(pszDumpData);
return dwError;
error:
goto cleanup;
}
DWORD
RegShellCmdParse(
PREGSHELL_PARSE_STATE pParseState,
DWORD argc,
PCHAR *argv,
PREGSHELL_CMD_ITEM *parsedCmd)
{
REGSHELL_CMD_E cmd = 0;
DWORD dwError = 0;
PSTR pszCommand = NULL;
PREGSHELL_CMD_ITEM pCmdItem = NULL;
BAIL_ON_INVALID_POINTER(argv);
if (argc < 2)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
pszCommand = argv[1];
dwError = RegShellCmdStringToEnum(pszCommand, &cmd);
switch (cmd)
{
/*
* Commands with no arguments
*/
case REGSHELL_CMD_HELP:
case REGSHELL_CMD_PWD:
if (argc > 2)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
else
{
dwError = RegShellCmdParseCommand(cmd, &pCmdItem);
}
break;
case REGSHELL_CMD_EXPORT:
dwError = RegShellCmdParseCommand(cmd, &pCmdItem);
BAIL_ON_REG_ERROR(dwError);
if (argc > 3)
{
dwError = RegShellCmdParseKeyName(
pParseState,
cmd,
argv[2],
&pCmdItem);
BAIL_ON_REG_ERROR(dwError);
dwError = RegAllocateMemory(
sizeof(PSTR) * 2,
(PVOID*)&pCmdItem->args);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(
(LW_PVOID) &pCmdItem->args[0], argv[3]);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->argsCount = 1;
}
else
{
dwError = RegAllocateMemory(
sizeof(PSTR) * 2,
(PVOID*)&pCmdItem->args);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(
(LW_PVOID) &pCmdItem->args[0], argv[2]);
}
break;
case REGSHELL_CMD_LIST_KEYS:
case REGSHELL_CMD_LIST:
case REGSHELL_CMD_DIRECTORY:
case REGSHELL_CMD_LIST_VALUES:
case REGSHELL_CMD_QUIT:
if (argc > 2)
{
dwError = RegShellCmdParseKeyName(
pParseState,
cmd,
argv[2],
&pCmdItem);
}
else
{
dwError = RegShellCmdParseCommand(cmd, &pCmdItem);
}
break;
case REGSHELL_CMD_IMPORT:
case REGSHELL_CMD_UPGRADE:
case REGSHELL_CMD_SET_HIVE:
if (argc != 3)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
dwError = RegShellCmdParseCommand(cmd, &pCmdItem);
BAIL_ON_REG_ERROR(dwError);
dwError = RegAllocateMemory(sizeof(PSTR) * 2, (PVOID*)&pCmdItem->args);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate((LW_PVOID) &pCmdItem->args[0], argv[2]);
BAIL_ON_REG_ERROR(dwError);
pCmdItem->argsCount = 1;
break;
/*
* Commands that take a KeyName argument
* command [HKLM_LIKEWISE/...]
*/
case REGSHELL_CMD_ADD_KEY:
case REGSHELL_CMD_CHDIR:
case REGSHELL_CMD_DELETE_KEY:
case REGSHELL_CMD_DELETE_TREE:
if (argc != 3)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
dwError = RegShellCmdParseKeyName(
pParseState,
cmd,
argv[2],
&pCmdItem);
break;
case REGSHELL_CMD_DELETE_VALUE:
if (argc > 4)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
dwError = RegShellCmdParseValueName(
pParseState,
cmd,
argc,
argv,
&pCmdItem);
break;
/*
* Commands that take ValueName/REG_TYPE/Values_List
* add_value "ValueName" type "Value" ["Value2"] ["Value3"] [...]
*/
case REGSHELL_CMD_ADD_VALUE:
if (argc < 5)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
case REGSHELL_CMD_SET_VALUE:
if (argc < 4)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
goto error;
}
dwError = RegShellCmdParseValueName(
pParseState,
cmd,
argc,
argv,
&pCmdItem);
break;
default:
dwError = LWREG_ERROR_INVALID_CONTEXT;
break;
}
*parsedCmd = pCmdItem;
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegShellAllocKey(
PSTR pszKeyName,
PSTR *pszNewKey)
{
DWORD dwError;
dwError = RegAllocateMemory(strlen(pszKeyName) + 3, (PVOID*)pszNewKey);
BAIL_ON_REG_ERROR(dwError);
strcpy(*pszNewKey, "[");
strcat(*pszNewKey, pszKeyName);
strcat(*pszNewKey, "]");
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
RegShellCmdlineParseToArgv(
PREGSHELL_PARSE_STATE pParseState,
PDWORD pdwNewArgc,
PSTR **pszNewArgv)
{
DWORD dwError = 0;
DWORD attrSize = 0;
DWORD dwArgc = 1;
DWORD dwAllocSize = 1;
DWORD dwBinaryDataOffset = 0;
DWORD dwLen = 0;
DWORD dwValueLen = 0;
DWORD dwKeyNameOffset = 0;
BOOLEAN eof = FALSE;
BOOLEAN stop = FALSE;
PSTR pszAttr = NULL;
PSTR pszPrevAttr = NULL;
PSTR *pszArgv = NULL;
PSTR *pszArgvRealloc = NULL;
PSTR pszBinaryData = NULL;
PSTR pszKeyName = NULL;
REGLEX_TOKEN token = 0;
REGSHELL_CMDLINE_STATE_E state = 0;
REG_DATA_TYPE valueType = REG_UNKNOWN;
REGSHELL_CMD_E cmdEnum = 0;
PREGSHELL_CMD_ITEM pCmdItem = NULL;
BAIL_ON_INVALID_HANDLE(pParseState->ioHandle);
BAIL_ON_INVALID_HANDLE(pParseState->lexHandle);
BAIL_ON_INVALID_POINTER(pdwNewArgc);
BAIL_ON_INVALID_POINTER(pszNewArgv);
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
stop = eof;
do
{
switch (state)
{
case REGSHELL_CMDLINE_STATE_FIRST:
if (token == REGLEX_PLAIN_TEXT)
{
state = REGSHELL_CMDLINE_STATE_VERB;
}
else
{
/* Syntax error */
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_VERB:
RegLexGetAttribute(pParseState->lexHandle, &attrSize, &pszAttr);
if (attrSize > 0)
{
dwError = RegShellCmdStringToEnum(pszAttr, &cmdEnum);
if (dwError)
{
/* Syntax error */
dwError = LWREG_ERROR_INVALID_CONTEXT;
break;
}
}
if (cmdEnum == REGSHELL_CMD_LIST_KEYS ||
cmdEnum == REGSHELL_CMD_LIST ||
cmdEnum == REGSHELL_CMD_DIRECTORY)
{
d_printf(("RegShellCmdlineParseToArgv: list_keys found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS;
dwArgc++;
dwAllocSize = dwArgc+1;
}
else if (cmdEnum == REGSHELL_CMD_LIST ||
cmdEnum == REGSHELL_CMD_DIRECTORY)
{
d_printf(("RegShellCmdlineParseToArgv: list found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS;
dwArgc++;
dwAllocSize = dwArgc+1;
}
else if (cmdEnum == REGSHELL_CMD_LIST_VALUES)
{
d_printf(("RegShellCmdlineParseToArgv: list_values found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS;
dwArgc++;
dwAllocSize = dwArgc+1;
}
else if (cmdEnum == REGSHELL_CMD_CHDIR)
{
d_printf(("RegShellCmdlineParseToArgv: cd found\n"));
state = REGSHELL_CMDLINE_STATE_CD;
dwArgc += 1;
dwAllocSize = dwArgc + 1;
}
else if (cmdEnum == REGSHELL_CMD_DELETE_KEY)
{
d_printf(("RegShellCmdlineParseToArgv: delete_key found\n"));
state = REGSHELL_CMDLINE_STATE_CD;
dwArgc += 1;
dwAllocSize = dwArgc + 1;
}
else if (cmdEnum == REGSHELL_CMD_DELETE_TREE)
{
d_printf(("RegShellCmdlineParseToArgv: delete_tree found\n"));
state = REGSHELL_CMDLINE_STATE_CD;
dwArgc += 1;
dwAllocSize = dwArgc + 1;
}
else if (cmdEnum == REGSHELL_CMD_HELP)
{
d_printf(("RegShellCmdlineParseToArgv: help found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP;
dwArgc += 1;
dwAllocSize = dwArgc;
}
else if (cmdEnum == REGSHELL_CMD_PWD)
{
d_printf(("RegShellCmdlineParseToArgv: pwd found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP;
dwArgc += 1;
dwAllocSize = dwArgc;
}
else if (cmdEnum == REGSHELL_CMD_QUIT)
{
d_printf(("RegShellCmdlineParseToArgv: exit found\n"));
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP;
dwArgc += 1;
dwAllocSize = dwArgc;
}
else if (cmdEnum == REGSHELL_CMD_ADD_KEY)
{
d_printf(("RegShellCmdlineParseToArgv: add_key found\n"));
state = REGSHELL_CMDLINE_STATE_ADDKEY;
dwArgc += 2;
dwAllocSize = dwArgc;
}
else if (cmdEnum == REGSHELL_CMD_ADD_VALUE)
{
d_printf(("RegShellCmdlineParseToArgv: add_value found\n"));
state = REGSHELL_CMDLINE_STATE_ADDVALUE;
dwArgc += 1;
/*
* Realloc pszArgv as needed for additional args,
* as there is no way to know how many arguments
* will follow for REG_MULTI_SZ.
*/
dwAllocSize = dwArgc + 64;
}
else if (cmdEnum == REGSHELL_CMD_DELETE_VALUE)
{
d_printf(("RegShellCmdlineParseToArgv: delete_value found\n"));
state = REGSHELL_CMDLINE_STATE_ADDVALUE;
dwArgc += 1;
dwAllocSize = dwArgc + 3;
}
else if (cmdEnum == REGSHELL_CMD_SET_VALUE)
{
d_printf(("RegShellCmdlineParseToArgv: set_value found\n"));
dwArgc += 1;
/*
* Realloc pszArgv as needed for additional args,
* as there is no way to know how many arguments
* will follow for REG_MULTI_SZ.
*/
state = REGSHELL_CMDLINE_STATE_ADDVALUE;
dwAllocSize = dwArgc + 64;
}
else if (cmdEnum == REGSHELL_CMD_SET_HIVE)
{
dwAllocSize = 4;
dwArgc = 2;
state = REGSHELL_CMDLINE_STATE_IMPORT;
}
else if (cmdEnum == REGSHELL_CMD_IMPORT)
{
dwAllocSize = 4;
dwArgc = 2;
state = REGSHELL_CMDLINE_STATE_IMPORT;
}
else if (cmdEnum == REGSHELL_CMD_EXPORT)
{
dwAllocSize = 4;
dwArgc = 2;
state = REGSHELL_CMDLINE_STATE_ADDVALUE;
}
else if (cmdEnum == REGSHELL_CMD_UPGRADE)
{
dwAllocSize = 4;
dwArgc = 2;
state = REGSHELL_CMDLINE_STATE_IMPORT;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
break;
}
dwError = RegAllocateMemory(sizeof(*pszArgv) * dwAllocSize, (PVOID*)&pszArgv);
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(&pszArgv[0], "regshell");
BAIL_ON_REG_ERROR(dwError);
dwError = RegCStringDuplicate(&pszArgv[1], pszAttr);
BAIL_ON_REG_ERROR(dwError);
break;
case REGSHELL_CMDLINE_STATE_LIST_KEYS:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
/*
* This parameter is optional, but there must have been a
* default key specified with a previous 'cd' command.
*/
if (!eof)
{
if (token == REGLEX_REG_KEY ||
token == REGLEX_PLAIN_TEXT)
{
dwArgc++;
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_REGKEY;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
}
else
{
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP;
stop = eof;
}
break;
case REGSHELL_CMDLINE_STATE_LIST_KEYS_REGKEY:
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
RegShellAllocKey(pszAttr, &pszArgv[dwArgc-1]);
BAIL_ON_REG_ERROR(dwError);
state = REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP;
break;
case REGSHELL_CMDLINE_STATE_LIST_KEYS_STOP:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
stop = eof;
if (!eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_CD:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
stop = eof;
}
else
{
if (token == REGLEX_REG_KEY ||
token == REGLEX_PLAIN_TEXT)
{
state = REGSHELL_CMDLINE_STATE_CD_REGKEY;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
}
break;
case REGSHELL_CMDLINE_STATE_CD_REGKEY:
dwError = RegShellAllocKey(pszAttr, &pszArgv[2]);
BAIL_ON_REG_ERROR(dwError);
dwArgc += 1;
state = REGSHELL_CMDLINE_STATE_CD_STOP;
break;
case REGSHELL_CMDLINE_STATE_CD_STOP:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
stop = eof;
if (!eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDKEY:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
stop = eof;
}
else
{
if (token == REGLEX_REG_KEY ||
token == REGLEX_PLAIN_TEXT)
{
state = REGSHELL_CMDLINE_STATE_ADDKEY_REGKEY;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
}
break;
case REGSHELL_CMDLINE_STATE_ADDKEY_REGKEY:
dwError = RegShellAllocKey(pszAttr, &pszArgv[2]);
BAIL_ON_REG_ERROR(dwError);
state = REGSHELL_CMDLINE_STATE_ADDKEY_STOP;
break;
case REGSHELL_CMDLINE_STATE_ADDKEY_STOP:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
stop = eof;
if (!eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else if (cmdEnum == REGSHELL_CMD_EXPORT &&
token == REGLEX_PLAIN_TEXT)
{
dwError = RegCStringDuplicate(&pszPrevAttr, pszAttr);
BAIL_ON_REG_ERROR(dwError);
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
if (eof)
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_VALUENAME;
}
else
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_KEYNAME;
}
RegLexUnGetToken(pParseState->lexHandle);
}
else if (token == REGLEX_REG_KEY)
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_KEYNAME;
}
else if (token == REGLEX_REG_SZ ||
token == REGLEX_PLAIN_TEXT ||
token == REGLEX_KEY_NAME_DEFAULT)
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_VALUENAME;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE_KEYNAME:
if (pszPrevAttr)
{
pszAttr = pszPrevAttr;
}
else
{
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
}
dwError = RegShellCmdParseKeyName(
pParseState,
cmdEnum,
pszAttr,
&pCmdItem);
LWREG_SAFE_FREE_MEMORY(pszPrevAttr);
BAIL_ON_REG_ERROR(dwError);
if (pCmdItem->keyName)
{
dwError = RegShellAllocKey(pCmdItem->keyName, &pszArgv[dwArgc++]);
BAIL_ON_REG_ERROR(dwError);
}
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else if (token == REGLEX_REG_SZ ||
token == REGLEX_PLAIN_TEXT ||
token == REGLEX_KEY_NAME_DEFAULT)
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_VALUENAME;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE_VALUENAME:
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
dwError = RegCStringDuplicate(&pszArgv[dwArgc++], pszAttr);
BAIL_ON_REG_ERROR(dwError);
if (cmdEnum == REGSHELL_CMD_SET_VALUE)
{
if (pCmdItem)
{
dwError = RegCStringDuplicate(&pszKeyName, pCmdItem->keyName ? pCmdItem->keyName : "");
BAIL_ON_REG_ERROR(dwError);
if (pszKeyName[0] == '\\')
{
dwKeyNameOffset++;
}
}
dwError = RegShellUtilGetValue(
NULL,
RegShellGetRootKey(pParseState),
RegShellGetDefaultKey(pParseState),
&pszKeyName[dwKeyNameOffset],
pszAttr,
&valueType,
NULL,
&dwValueLen);
BAIL_ON_REG_ERROR(dwError);
state = REGSHELL_CMDLINE_STATE_ADDVALUE_VALUE;
break;
}
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
/* add_value type is next */
if (cmdEnum == REGSHELL_CMD_DELETE_VALUE ||
cmdEnum == REGSHELL_CMD_EXPORT)
{
stop = TRUE;
}
else if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else if (token == REGLEX_REG_SZ ||
token == REGLEX_PLAIN_TEXT ||
token == REGLEX_REG_MULTI_SZ ||
token == REGLEX_REG_BINARY ||
token == REGLEX_REG_DWORD)
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_TYPE;
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE_TYPE:
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
dwError = RegShellParseStringType(
pszAttr,
&valueType,
NULL);
if (valueType == REG_UNKNOWN)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
BAIL_ON_REG_ERROR(dwError);
}
dwError = RegCStringDuplicate(&pszArgv[dwArgc++], pszAttr);
BAIL_ON_REG_ERROR(dwError);
state = REGSHELL_CMDLINE_STATE_ADDVALUE_VALUE;
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE_VALUE:
/* Get current buffer before reading the next token
* to determine if EOF has been found. Do this before
* the next call to RegLexGetToken(), as it consumes
* the first hex pair if found.
*/
if (valueType == REG_BINARY || REG_DWORD)
{
dwError = RegIOBufferGetData(
pParseState->ioHandle,
&pszBinaryData,
NULL,
&dwBinaryDataOffset);
BAIL_ON_REG_ERROR(dwError);
}
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
if ((cmdEnum==REGSHELL_CMD_SET_VALUE && dwArgc<=3) ||
(cmdEnum== REGSHELL_CMD_ADD_VALUE && dwArgc<=4))
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else
{
state = REGSHELL_CMDLINE_STATE_ADDVALUE_STOP;
}
}
else if (valueType == REG_BINARY || valueType == REG_DWORD)
{
dwError = RegCStringDuplicate(
&pszArgv[dwArgc],
&pszBinaryData[dwBinaryDataOffset]);
BAIL_ON_REG_ERROR(dwError);
dwLen = strlen(pszArgv[dwArgc]);
if (dwLen>1 && pszArgv[dwArgc][dwLen-1] == '\n')
{
pszArgv[dwArgc][dwLen-1] = '\0';
}
dwArgc++;
/*
* Force a stop now, as the parser will return
* subsequent hex pairs, which is not what we want.
* Call RegLexResetToken() to flush the remainder
* of the command line from the parser.
*/
stop = TRUE;
RegLexResetToken(pParseState->lexHandle);
}
else if (token == REGLEX_REG_SZ ||
token == REGLEX_PLAIN_TEXT)
{
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
dwError = RegCStringDuplicate(&pszArgv[dwArgc++], pszAttr);
BAIL_ON_REG_ERROR(dwError);
if (dwArgc >= dwAllocSize)
{
dwAllocSize *= 2;
dwError = RegReallocMemory(
pszArgv,
(LW_PVOID) &pszArgvRealloc,
dwAllocSize * sizeof(PSTR *));
BAIL_ON_REG_ERROR(dwError);
pszArgv = pszArgvRealloc;
pszArgvRealloc = NULL;
}
}
else
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
break;
case REGSHELL_CMDLINE_STATE_ADDVALUE_STOP:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (!eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else
{
stop = TRUE;
}
break;
case REGSHELL_CMDLINE_STATE_IMPORT:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else
{
state = REGSHELL_CMDLINE_STATE_IMPORT_FILE;
}
break;
case REGSHELL_CMDLINE_STATE_IMPORT_FILE:
RegLexGetAttribute(pParseState->lexHandle,
&attrSize,
&pszAttr);
dwError = RegCStringDuplicate((LW_PVOID) &pszArgv[dwArgc++],
pszAttr);
BAIL_ON_REG_ERROR(dwError);
state = REGSHELL_CMDLINE_STATE_IMPORT_STOP;
break;
case REGSHELL_CMDLINE_STATE_IMPORT_STOP:
dwError = RegLexGetToken(pParseState->ioHandle,
pParseState->lexHandle,
&token,
&eof);
BAIL_ON_REG_ERROR(dwError);
if (!eof)
{
dwError = LWREG_ERROR_INVALID_CONTEXT;
}
else
{
stop = eof;
}
break;
default:
stop = TRUE;
break;
}
}
while (!stop && dwError == ERROR_SUCCESS);
*pdwNewArgc = dwArgc;
*pszNewArgv = pszArgv;
#ifdef _LW_DEBUG
if (pszArgv)
{
int i;
for (i=0; ilexHandle);
}
return dwError;
error:
RegShellCmdlineParseFree(dwArgc, pszArgv);
goto cleanup;
}
DWORD
RegShellCmdlineParseFree(
DWORD dwArgc,
PSTR *pszArgv)
{
DWORD dwError = 0;
DWORD i = 0;
BAIL_ON_INVALID_POINTER(pszArgv);
for (i=0; i