316 lines
8.1 KiB
C
316 lines
8.1 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:
|
|
|
|
--*/
|
|
|
|
#pragma warning(disable:4127) // condition expression is constant
|
|
|
|
#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 = 0;
|
|
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 (TRUE) {
|
|
len = NextElement(&input,
|
|
&inLen,
|
|
element,
|
|
sizeof(element) - sizeof(element[0]),
|
|
BlankIsDelimiter );
|
|
if (len == (ULONG)-1L) {
|
|
cLen = 0;
|
|
ok = FALSE;
|
|
} else {
|
|
if (len == 0) {
|
|
break;
|
|
}
|
|
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-delimiter) 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 (inputLength && IS_DELIMITER(*input, BlankIsDelimiter)) {
|
|
++input;
|
|
inputLength -= sizeof(*input);
|
|
}
|
|
while (inputLength && (!IS_DELIMITER(*input, BlankIsDelimiter))) {
|
|
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);
|
|
}
|