612 lines
16 KiB
C++
612 lines
16 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
|
//
|
|
// File: parserutil.cpp
|
|
//
|
|
// Contents: Helpful functions for manipulating and validating
|
|
// generic command line arguments
|
|
//
|
|
// History: 07-Sep-2000 JeffJon Created
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include "pch.h"
|
|
#include "iostream.h"
|
|
#include "cstrings.h"
|
|
#include "commonstrings.h"
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: GetPasswdStr
|
|
//
|
|
// Synopsis: Reads a password string from stdin without echoing the keystrokes
|
|
//
|
|
// Arguments: [buf - OUT] : buffer to put string in
|
|
// [buflen - IN] : size of the buffer
|
|
// [&len - OUT] : length of the string placed into the buffer
|
|
//
|
|
// Returns: DWORD : 0 or ERROR_INSUFFICIENT_BUFFER if user typed too much.
|
|
// Buffer contents are only valid on 0 return.
|
|
//
|
|
// History: 07-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#define CR 0xD
|
|
#define BACKSPACE 0x8
|
|
|
|
DWORD GetPasswdStr(LPTSTR buf,
|
|
DWORD buflen,
|
|
PDWORD len)
|
|
{
|
|
TCHAR ch;
|
|
TCHAR *bufPtr = buf;
|
|
DWORD c;
|
|
int err;
|
|
DWORD mode;
|
|
|
|
buflen -= 1; /* make space for null terminator */
|
|
*len = 0; /* GP fault probe (a la API's) */
|
|
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
|
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
|
|
(~(ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT)) & mode);
|
|
|
|
while (TRUE)
|
|
{
|
|
//Security Review:Correct buffer len is passed.
|
|
err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &ch, 1, &c, 0);
|
|
if (!err || c != 1)
|
|
ch = 0xffff;
|
|
|
|
if ((ch == CR) || (ch == 0xffff)) /* end of the line */
|
|
break;
|
|
|
|
if (ch == BACKSPACE)
|
|
{ /* back up one or two */
|
|
/*
|
|
* IF bufPtr == buf then the next two lines are
|
|
* a no op.
|
|
*/
|
|
if (bufPtr != buf)
|
|
{
|
|
bufPtr--;
|
|
(*len)--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*bufPtr = ch;
|
|
|
|
if (*len < buflen)
|
|
bufPtr++ ; /* don't overflow buf */
|
|
(*len)++; /* always increment len */
|
|
}
|
|
}
|
|
|
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode);
|
|
*bufPtr = TEXT('\0'); /* null terminate the string */
|
|
putwchar(TEXT('\n'));
|
|
|
|
return ((*len <= buflen) ? 0 : ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidatePassword
|
|
//
|
|
// Synopsis: Password validation function called by parser
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : ERROR_INVALID_PARAMETER if the argument record or
|
|
// the value it contains is not valid
|
|
// ERROR_NOT_ENOUGH_MEMORY
|
|
// ERROR_SUCCESS if everything succeeded and it is a
|
|
// valid password
|
|
// Otherwise it is an error condition returned from
|
|
// GetPasswdStr
|
|
//
|
|
// History: 07-Sep-2000 JeffJon Created
|
|
// 03-27-2002 hiteshr changed the function
|
|
// //NTRAID#NTBUG9-571544-2000/11/13-hiteshr
|
|
//---------------------------------------------------------------------------
|
|
DWORD ValidatePassword(PVOID pArg,
|
|
UINT IdStr,
|
|
UINT IdPromptConfirm)
|
|
{
|
|
|
|
PARG_RECORD pRec = (PARG_RECORD)pArg;
|
|
if(!pRec || !pRec->strValue)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//Validate the length of password. Password length must be
|
|
//less than MAX_PASSWORD_LENGTH
|
|
size_t cchInputPassword = 0;
|
|
HRESULT hr = StringCchLength(pRec->strValue,
|
|
MAX_PASSWORD_LENGTH,
|
|
&cchInputPassword);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DisplayErrorMessage(g_pszDSCommandName,NULL,E_INVALIDARG,IDS_ERROR_LONG_PASSWORD);
|
|
return VLDFN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
//If Password is *, store encrypted password
|
|
if(wcscmp(pRec->strValue, L"*") != 0 )
|
|
{
|
|
DATA_BLOB EncryptedPasswordDataBlob;
|
|
hr = EncryptPasswordString(pRec->strValue, &EncryptedPasswordDataBlob);
|
|
|
|
//Clear the cleartext password
|
|
SecureZeroMemory(pRec->strValue,cchInputPassword*sizeof(WCHAR));
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LocalFree(pRec->strValue);
|
|
pRec->encryptedDataBlob = EncryptedPasswordDataBlob;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//User entered * in commandline. Prompt for password.
|
|
CComBSTR sbstrPrompt;
|
|
if(sbstrPrompt.LoadString(::GetModuleHandle(NULL),IdStr))
|
|
{
|
|
DisplayOutput(sbstrPrompt);
|
|
}
|
|
else
|
|
DisplayOutput(L"Enter Password\n");
|
|
|
|
WCHAR buffer[MAX_PASSWORD_LENGTH];
|
|
DWORD len = 0;
|
|
DWORD dwErr = GetPasswdStr(buffer,MAX_PASSWORD_LENGTH,&len);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
return dwErr;
|
|
|
|
if(IdPromptConfirm)
|
|
{
|
|
if(sbstrPrompt.LoadString(::GetModuleHandle(NULL),IdPromptConfirm))
|
|
{
|
|
DisplayOutput(sbstrPrompt);
|
|
}
|
|
else
|
|
DisplayOutput(L"Confirm Password\n");
|
|
|
|
WCHAR buffer1[MAX_PASSWORD_LENGTH];
|
|
DWORD len1 = 0;
|
|
dwErr = GetPasswdStr(buffer1,MAX_PASSWORD_LENGTH,&len1);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
return dwErr;
|
|
|
|
//Security Review:This is fine.
|
|
if(wcscmp(buffer,buffer1) != 0)
|
|
{
|
|
SecureZeroMemory(buffer,sizeof(buffer));
|
|
SecureZeroMemory(buffer1,sizeof(buffer1));
|
|
CComBSTR sbstrError;
|
|
sbstrError.LoadString(::GetModuleHandle(NULL),IDS_ERROR_PASSWORD_MISSMATCH);
|
|
|
|
DisplayErrorMessage(g_pszDSCommandName,NULL,S_OK,sbstrError);
|
|
//Security Review:SecureZeroMemory buffer and buffer1 before returning
|
|
return VLDFN_ERROR_NO_ERROR;
|
|
}
|
|
|
|
//Two passwords are same. Clear the buffer1
|
|
SecureZeroMemory(buffer1,sizeof(buffer1));
|
|
}
|
|
|
|
//CryptProtectMemory strValue
|
|
DATA_BLOB EncryptedPasswordDataBlob;
|
|
hr = EncryptPasswordString(buffer, &EncryptedPasswordDataBlob);
|
|
//Clear the cleartext password in buffer
|
|
SecureZeroMemory(buffer,sizeof(buffer));
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LocalFree(pRec->strValue);
|
|
pRec->encryptedDataBlob = EncryptedPasswordDataBlob;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateAdminPassword
|
|
//
|
|
// Synopsis: Password validation function called by parser for Admin
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : ERROR_INVALID_PARAMETER if the argument record or
|
|
// the value it contains is not valid
|
|
// ERROR_SUCCESS if everything succeeded and it is a
|
|
// valid password
|
|
//
|
|
// History: 07-Sep-2000 Hiteshr Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
DWORD ValidateAdminPassword(PVOID pArg)
|
|
{
|
|
return ValidatePassword(pArg,IDS_ADMIN_PASSWORD_PROMPT,0);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateUserPassword
|
|
//
|
|
// Synopsis: Password validation function called by parser for Admin
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : Same as ValidatePassword
|
|
//
|
|
// History: 07-Sep-2000 Hiteshr Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
DWORD ValidateUserPassword(PVOID pArg)
|
|
{
|
|
return ValidatePassword(pArg, IDS_USER_PASSWORD_PROMPT,IDS_USER_PASSWORD_CONFIRM);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateYesNo
|
|
//
|
|
// Synopsis: Password validation function called by parser for Admin
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : Same as ValidatePassword
|
|
//
|
|
// History: 07-Sep-2000 Hiteshr Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
DWORD ValidateYesNo(PVOID pArg)
|
|
{
|
|
PARG_RECORD pRec = (PARG_RECORD)pArg;
|
|
if(!pRec || !pRec->strValue)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
CComBSTR sbstrInput;
|
|
|
|
sbstrInput = pRec->strValue;
|
|
sbstrInput.ToLower();
|
|
if( sbstrInput == g_bstrYes )
|
|
{
|
|
LocalFree(pRec->strValue);
|
|
pRec->bValue = TRUE;
|
|
}
|
|
else if( sbstrInput == g_bstrNo )
|
|
{
|
|
LocalFree(pRec->strValue);
|
|
pRec->bValue = FALSE;
|
|
}
|
|
else
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// Have to set this to bool or else
|
|
// FreeCmd will try to free the string
|
|
// which AVs when the bool is true
|
|
//
|
|
pRec->fType = ARG_TYPE_BOOL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateNever
|
|
//
|
|
// Synopsis: Password validation function called by parser for Admin
|
|
// Verifies the value contains digits or "NEVER"
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : Same as ValidatePassword
|
|
//
|
|
// History: 07-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
DWORD ValidateNever(PVOID pArg)
|
|
{
|
|
PARG_RECORD pRec = (PARG_RECORD)pArg;
|
|
if(!pRec)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if (pRec->fType == ARG_TYPE_STR)
|
|
{
|
|
CComBSTR sbstrInput;
|
|
sbstrInput = pRec->strValue;
|
|
//Security Review:This is fine, though we don't need
|
|
//to copy it sbstrInput. A direct comparison should be
|
|
//good enough.
|
|
if( _wcsicmp(sbstrInput, g_bstrNever) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateGroupScope
|
|
//
|
|
// Synopsis: Makes sure that the value following the -scope switch is one
|
|
// of (l/g/u)
|
|
//
|
|
// Arguments: [pArg - IN] : pointer argument structure which contains
|
|
// the value to be validated
|
|
//
|
|
// Returns: DWORD : Same as ValidatePassword
|
|
//
|
|
// History: 18-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
DWORD ValidateGroupScope(PVOID pArg)
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
PARG_RECORD pRec = (PARG_RECORD)pArg;
|
|
if(!pRec || !pRec->strValue)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
CComBSTR sbstrInput;
|
|
sbstrInput = pRec->strValue;
|
|
sbstrInput.ToLower();
|
|
if(sbstrInput == _T("l") ||
|
|
sbstrInput == _T("g") ||
|
|
sbstrInput == _T("u"))
|
|
{
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: MergeArgCommand
|
|
//
|
|
// Synopsis: Combines two ARG_RECORD arrays into a single
|
|
//
|
|
// Arguments: [pCommand1 - IN] : first ARG_RECORD array to merge
|
|
// [pCommand2 - IN] : second ARG_RECORD array to merge
|
|
// [ppOutCommand - OUT] : the array that results from the merge
|
|
//
|
|
// Returns: HRESULT : S_OK on success
|
|
// E_OUTOFMEMORY if failed to allocate memory for new array
|
|
//
|
|
// History: 08-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
HRESULT MergeArgCommand(PARG_RECORD pCommand1,
|
|
PARG_RECORD pCommand2,
|
|
PARG_RECORD *ppOutCommand)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Verify parameters
|
|
//
|
|
if (!pCommand1 && !pCommand2)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LONG nSize1 = 0;
|
|
LONG nSize2 = 0;
|
|
|
|
UINT i = 0;
|
|
|
|
if (NULL != pCommand1)
|
|
{
|
|
for(i=0; pCommand1[i].fType != ARG_TYPE_LAST ;i++)
|
|
{
|
|
++nSize1;
|
|
}
|
|
}
|
|
if (NULL != pCommand2)
|
|
{
|
|
for(i=0; pCommand2[i].fType != ARG_TYPE_LAST ;i++)
|
|
{
|
|
++nSize2;
|
|
}
|
|
}
|
|
|
|
*ppOutCommand = (PARG_RECORD)LocalAlloc(LPTR, sizeof(ARG_RECORD)*(nSize1+nSize2+1));
|
|
if(!*ppOutCommand)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (NULL != pCommand1)
|
|
{
|
|
//Security Review:This is fine.
|
|
memcpy(*ppOutCommand,pCommand1,sizeof(ARG_RECORD)*(nSize1+1));
|
|
}
|
|
if (NULL != pCommand2)
|
|
{
|
|
//Security Review:This is fine.
|
|
memcpy((*ppOutCommand+nSize1),pCommand2,sizeof(ARG_RECORD)*(nSize2+1));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseStringByChar
|
|
//
|
|
// Synopsis: Parses a string into elements separated by the given character
|
|
//
|
|
// Arguments: [psz - IN] : string to be parsed
|
|
// [tchar - IN] : character that is to be used as the separator
|
|
// [pszArr - OUT] : the array to receive the parsed strings
|
|
// [pnArrEntries - OUT] : the number of strings parsed from the list
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 18-Sep-2000 JeffJon Created
|
|
// 14-Apr-2001 JeffJon Modified to separate on a generic character
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void ParseStringByChar(PTSTR psz,
|
|
TCHAR tchar,
|
|
PTSTR** ppszArr,
|
|
UINT* pnArrEntries)
|
|
{
|
|
//
|
|
// Verify parameters
|
|
//
|
|
if (!psz ||
|
|
!ppszArr ||
|
|
!pnArrEntries)
|
|
{
|
|
ASSERT(psz);
|
|
ASSERT(ppszArr);
|
|
ASSERT(pnArrEntries);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Count the number of strings
|
|
//
|
|
UINT nCount = 0;
|
|
PTSTR pszTemp = psz;
|
|
while (true)
|
|
{
|
|
if (pszTemp[0] == tchar &&
|
|
pszTemp[1] == tchar)
|
|
{
|
|
nCount++;
|
|
break;
|
|
}
|
|
else if (pszTemp[0] == tchar &&
|
|
pszTemp[1] != tchar)
|
|
{
|
|
nCount++;
|
|
pszTemp++;
|
|
}
|
|
else
|
|
{
|
|
pszTemp++;
|
|
}
|
|
}
|
|
|
|
*pnArrEntries = nCount;
|
|
|
|
//
|
|
// Allocate the array
|
|
//
|
|
*ppszArr = (PTSTR*)LocalAlloc(LPTR, nCount * sizeof(PTSTR));
|
|
if (*ppszArr)
|
|
{
|
|
//
|
|
// Copy the string pointers into the array
|
|
//
|
|
UINT nIdx = 0;
|
|
pszTemp = psz;
|
|
(*ppszArr)[nIdx] = pszTemp;
|
|
nIdx++;
|
|
|
|
while (true)
|
|
{
|
|
if (pszTemp[0] == tchar &&
|
|
pszTemp[1] == tchar)
|
|
{
|
|
break;
|
|
}
|
|
else if (pszTemp[0] == tchar &&
|
|
pszTemp[1] != tchar)
|
|
{
|
|
(*ppszArr)[nIdx] = &(pszTemp[1]);
|
|
nIdx++;
|
|
pszTemp++;
|
|
}
|
|
else
|
|
{
|
|
pszTemp++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseNullSeparatedString
|
|
//
|
|
// Synopsis: Parses a '\0' separated list that ends in "\0\0" into a string
|
|
// array
|
|
//
|
|
// Arguments: [psz - IN] : '\0' separated string to be parsed
|
|
// [pszArr - OUT] : the array to receive the parsed strings
|
|
// [pnArrEntries - OUT] : the number of strings parsed from the list
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 14-Apr-2001 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void ParseNullSeparatedString(PTSTR psz,
|
|
PTSTR** ppszArr,
|
|
UINT* pnArrEntries)
|
|
{
|
|
ParseStringByChar(psz,
|
|
L'\0',
|
|
ppszArr,
|
|
pnArrEntries);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseSemicolonSeparatedString
|
|
//
|
|
// Synopsis: Parses a ';' separated list
|
|
//
|
|
// Arguments: [psz - IN] : ';' separated string to be parsed
|
|
// [pszArr - OUT] : the array to receive the parsed strings
|
|
// [pnArrEntries - OUT] : the number of strings parsed from the list
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 14-Apr-2001 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void ParseSemicolonSeparatedString(PTSTR psz,
|
|
PTSTR** ppszArr,
|
|
UINT* pnArrEntries)
|
|
{
|
|
ParseStringByChar(psz,
|
|
L';',
|
|
ppszArr,
|
|
pnArrEntries);
|
|
}
|
|
|
|
|