Windows-Server-2003/admin/dscmd/parserutil.cpp

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);
}