windows-nt/Source/XPSP1/NT/base/ntdll/uilist.c
2020-09-26 16:20:57 +08:00

306 lines
7.9 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
uilist.c
Abstract:
Contains routine to convert a list of workstation names from UI/Service
list format to API list format
Contents:
RtlConvertUiListToApiList
(NextElement)
(ValidateName)
Author:
Richard L Firth (rfirth) 01-May-1992
Environment:
User mode (makes Windows calls)
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wchar.h>
//
// macros
//
#define IS_DELIMITER(c,_BlankOk) \
(((c) == L' ' && (_BlankOk)) || \
((c) == L'\t') || ((c) == L',') || ((c) == L';'))
//
// prototypes
//
static
ULONG
NextElement(
IN OUT PWSTR* InputBuffer,
IN OUT PULONG InputBufferLength,
OUT PWSTR OutputBuffer,
IN ULONG OutputBufferLength,
IN BOOLEAN BlankIsDelimiter
);
static
BOOLEAN
ValidateName(
IN PWSTR Name,
IN ULONG Length
);
//
// functions
//
NTSTATUS
RtlConvertUiListToApiList(
IN PUNICODE_STRING UiList OPTIONAL,
OUT PUNICODE_STRING ApiList,
IN BOOLEAN BlankIsDelimiter
)
/*++
Routine Description:
Converts a list of workstation names in UI/Service format into a list of
canonicalized names in API list format. UI/Service list format allows
multiple delimiters, leading and trailing delimiters. Delimiters are the
set "\t,;". API list format has no leading or trailing delimiters and
elements are delimited by a single comma character.
For each name parsed from UiList, the name is canonicalized (which checks
the character set and name length) as a workstation name. If this fails,
an error is returned. No information is returned as to which element
failed canonicalization: the list should be discarded and a new one re-input
Arguments:
UiList - The list to canonicalize in UI/Service list format
ApiList - The place to store the canonicalized version of the list in
API list format. The list will have a trailing zero character.
BlankIsDelimiter - TRUE indicates blank should be considered a delimiter
character.
Return Value:
NTSTATUS
Success = STATUS_SUCCESS
List converted ok
Failure = STATUS_INVALID_PARAMETER
UiList parameter is in error
STATUS_INVALID_COMPUTER_NAME
A name parsed from UiList has an incorrect format for a
computer (aka workstation) name
--*/
{
NTSTATUS status = STATUS_SUCCESS;
ULONG inLen;
PWSTR input;
PWSTR buffer;
PWSTR output;
ULONG cLen;
ULONG len;
ULONG outLen = 0;
WCHAR element[MAX_COMPUTERNAME_LENGTH+1];
BOOLEAN firstElement = TRUE;
BOOLEAN ok;
try {
if (ARGUMENT_PRESENT(UiList)) {
inLen = UiList->MaximumLength; // read memory test
inLen = UiList->Length;
input = UiList->Buffer;
if (inLen & sizeof(WCHAR)-1) {
status = STATUS_INVALID_PARAMETER;
}
}
RtlInitUnicodeString(ApiList, NULL);
} except (EXCEPTION_EXECUTE_HANDLER) {
status = STATUS_ACCESS_VIOLATION;
}
if (NT_SUCCESS(status) && ARGUMENT_PRESENT(UiList) && inLen) {
buffer = RtlAllocateHeap(RtlProcessHeap(), 0, inLen + sizeof(WCHAR));
if (buffer == NULL) {
status = STATUS_NO_MEMORY;
} else {
ApiList->Buffer = buffer;
ApiList->MaximumLength = (USHORT)inLen + sizeof(WCHAR);
output = buffer;
ok = TRUE;
while (len = NextElement(&input,
&inLen,
element,
sizeof(element) - sizeof(element[0]),
BlankIsDelimiter )) {
if (len == (ULONG)-1L) {
ok = FALSE;
} else {
cLen = len/sizeof(WCHAR);
element[cLen] = 0;
ok = ValidateName(element, cLen);
}
if (ok) {
if (!firstElement) {
*output++ = L',';
outLen += sizeof(WCHAR);
} else {
firstElement = FALSE;
}
wcscpy(output, element);
outLen += len;
output += cLen;
} else {
RtlFreeHeap(RtlProcessHeap(), 0, buffer);
ApiList->Buffer = NULL;
status = STATUS_INVALID_COMPUTER_NAME;
break;
}
}
}
if (NT_SUCCESS(status)) {
ApiList->Length = (USHORT)outLen;
if (!outLen) {
ApiList->MaximumLength = 0;
ApiList->Buffer = NULL;
RtlFreeHeap(RtlProcessHeap(), 0, buffer);
}
}
}
return status;
}
static
ULONG
NextElement(
IN OUT PWSTR* InputBuffer,
IN OUT PULONG InputBufferLength,
OUT PWSTR OutputBuffer,
IN ULONG OutputBufferLength,
IN BOOLEAN BlankIsDelimiter
)
/*++
Routine Description:
Locates the next (non-delimter) element in a string and extracts it to a
buffer. Delimiters are the set [\t,;]
Arguments:
InputBuffer - pointer to pointer to input buffer including delimiters
Updated on successful return
InputBufferLength - pointer to length of characters in InputBuffer.
Updated on successful return
OutputBuffer - pointer to buffer where next element is copied
OutputBufferLength - size of OutputBuffer (in bytes)
BlankIsDelimiter - TRUE indicates blank should be considered a delimiter
character.
Return Value:
ULONG
-1 = error - extracted element breaks OutputBuffer
0 = no element extracted (buffer is empty or all
delimiters)
1..OutputBufferLength = OutputBuffer contains extracted element
--*/
{
ULONG elementLength = 0;
ULONG inputLength = *InputBufferLength;
PWSTR input = *InputBuffer;
while (IS_DELIMITER(*input, BlankIsDelimiter) && inputLength) {
++input;
inputLength -= sizeof(*input);
}
while (!IS_DELIMITER(*input, BlankIsDelimiter) && inputLength) {
if (!OutputBufferLength) {
return (ULONG)-1L;
}
*OutputBuffer++ = *input++;
OutputBufferLength -= sizeof(*input);
elementLength += sizeof(*input);
inputLength -= sizeof(*input);
}
*InputBuffer = input;
*InputBufferLength = inputLength;
return elementLength;
}
//
// Illegal names characters same as those in net\api. Move to common
// include directory
//
#define ILLEGAL_NAME_CHARS L"\001\002\003\004\005\006\007" \
L"\010\011\012\013\014\015\016\017" \
L"\020\021\022\023\024\025\026\027" \
L"\030\031\032\033\034\035\036\037" \
L"\"/\\[]:|<>+=;,?*"
static
BOOLEAN
ValidateName(
IN PWSTR Name,
IN ULONG Length
)
/*++
Routine Description:
Determines whether a computer name is valid or not
Arguments:
Name - pointer to zero terminated wide-character computer name
Length - of Name in characters, excluding zero-terminator
Return Value:
BOOLEAN
TRUE Name is valid computer name
FALSE Name is not valid computer name
--*/
{
if (Length > MAX_COMPUTERNAME_LENGTH || Length < 1) {
return FALSE;
}
//
// Don't allow leading or trailing blanks in the computername.
//
if ( Name[0] == ' ' || Name[Length-1] == ' ' ) {
return(FALSE);
}
return (BOOLEAN)((ULONG)wcscspn(Name, ILLEGAL_NAME_CHARS) == Length);
}