Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. uilist.c
  5. Abstract:
  6. Contains routine to convert a list of workstation names from UI/Service
  7. list format to API list format
  8. Contents:
  9. RtlConvertUiListToApiList
  10. (NextElement)
  11. (ValidateName)
  12. Author:
  13. Richard L Firth (rfirth) 01-May-1992
  14. Environment:
  15. User mode (makes Windows calls)
  16. Revision History:
  17. --*/
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <wchar.h>
  23. //
  24. // macros
  25. //
  26. #define IS_DELIMITER(c,_BlankOk) \
  27. (((c) == L' ' && (_BlankOk)) || \
  28. ((c) == L'\t') || ((c) == L',') || ((c) == L';'))
  29. //
  30. // prototypes
  31. //
  32. static
  33. ULONG
  34. NextElement(
  35. IN OUT PWSTR* InputBuffer,
  36. IN OUT PULONG InputBufferLength,
  37. OUT PWSTR OutputBuffer,
  38. IN ULONG OutputBufferLength,
  39. IN BOOLEAN BlankIsDelimiter
  40. );
  41. static
  42. BOOLEAN
  43. ValidateName(
  44. IN PWSTR Name,
  45. IN ULONG Length
  46. );
  47. //
  48. // functions
  49. //
  50. NTSTATUS
  51. RtlConvertUiListToApiList(
  52. IN PUNICODE_STRING UiList OPTIONAL,
  53. OUT PUNICODE_STRING ApiList,
  54. IN BOOLEAN BlankIsDelimiter
  55. )
  56. /*++
  57. Routine Description:
  58. Converts a list of workstation names in UI/Service format into a list of
  59. canonicalized names in API list format. UI/Service list format allows
  60. multiple delimiters, leading and trailing delimiters. Delimiters are the
  61. set "\t,;". API list format has no leading or trailing delimiters and
  62. elements are delimited by a single comma character.
  63. For each name parsed from UiList, the name is canonicalized (which checks
  64. the character set and name length) as a workstation name. If this fails,
  65. an error is returned. No information is returned as to which element
  66. failed canonicalization: the list should be discarded and a new one re-input
  67. Arguments:
  68. UiList - The list to canonicalize in UI/Service list format
  69. ApiList - The place to store the canonicalized version of the list in
  70. API list format. The list will have a trailing zero character.
  71. BlankIsDelimiter - TRUE indicates blank should be considered a delimiter
  72. character.
  73. Return Value:
  74. NTSTATUS
  75. Success = STATUS_SUCCESS
  76. List converted ok
  77. Failure = STATUS_INVALID_PARAMETER
  78. UiList parameter is in error
  79. STATUS_INVALID_COMPUTER_NAME
  80. A name parsed from UiList has an incorrect format for a
  81. computer (aka workstation) name
  82. --*/
  83. {
  84. NTSTATUS status = STATUS_SUCCESS;
  85. ULONG inLen;
  86. PWSTR input;
  87. PWSTR buffer;
  88. PWSTR output;
  89. ULONG cLen;
  90. ULONG len;
  91. ULONG outLen = 0;
  92. WCHAR element[MAX_COMPUTERNAME_LENGTH+1];
  93. BOOLEAN firstElement = TRUE;
  94. BOOLEAN ok;
  95. try {
  96. if (ARGUMENT_PRESENT(UiList)) {
  97. inLen = UiList->MaximumLength; // read memory test
  98. inLen = UiList->Length;
  99. input = UiList->Buffer;
  100. if (inLen & sizeof(WCHAR)-1) {
  101. status = STATUS_INVALID_PARAMETER;
  102. }
  103. }
  104. RtlInitUnicodeString(ApiList, NULL);
  105. } except (EXCEPTION_EXECUTE_HANDLER) {
  106. status = STATUS_ACCESS_VIOLATION;
  107. }
  108. if (NT_SUCCESS(status) && ARGUMENT_PRESENT(UiList) && inLen) {
  109. buffer = RtlAllocateHeap(RtlProcessHeap(), 0, inLen + sizeof(WCHAR));
  110. if (buffer == NULL) {
  111. status = STATUS_NO_MEMORY;
  112. } else {
  113. ApiList->Buffer = buffer;
  114. ApiList->MaximumLength = (USHORT)inLen + sizeof(WCHAR);
  115. output = buffer;
  116. ok = TRUE;
  117. while (len = NextElement(&input,
  118. &inLen,
  119. element,
  120. sizeof(element) - sizeof(element[0]),
  121. BlankIsDelimiter )) {
  122. if (len == (ULONG)-1L) {
  123. ok = FALSE;
  124. } else {
  125. cLen = len/sizeof(WCHAR);
  126. element[cLen] = 0;
  127. ok = ValidateName(element, cLen);
  128. }
  129. if (ok) {
  130. if (!firstElement) {
  131. *output++ = L',';
  132. outLen += sizeof(WCHAR);
  133. } else {
  134. firstElement = FALSE;
  135. }
  136. wcscpy(output, element);
  137. outLen += len;
  138. output += cLen;
  139. } else {
  140. RtlFreeHeap(RtlProcessHeap(), 0, buffer);
  141. ApiList->Buffer = NULL;
  142. status = STATUS_INVALID_COMPUTER_NAME;
  143. break;
  144. }
  145. }
  146. }
  147. if (NT_SUCCESS(status)) {
  148. ApiList->Length = (USHORT)outLen;
  149. if (!outLen) {
  150. ApiList->MaximumLength = 0;
  151. ApiList->Buffer = NULL;
  152. RtlFreeHeap(RtlProcessHeap(), 0, buffer);
  153. }
  154. }
  155. }
  156. return status;
  157. }
  158. static
  159. ULONG
  160. NextElement(
  161. IN OUT PWSTR* InputBuffer,
  162. IN OUT PULONG InputBufferLength,
  163. OUT PWSTR OutputBuffer,
  164. IN ULONG OutputBufferLength,
  165. IN BOOLEAN BlankIsDelimiter
  166. )
  167. /*++
  168. Routine Description:
  169. Locates the next (non-delimter) element in a string and extracts it to a
  170. buffer. Delimiters are the set [\t,;]
  171. Arguments:
  172. InputBuffer - pointer to pointer to input buffer including delimiters
  173. Updated on successful return
  174. InputBufferLength - pointer to length of characters in InputBuffer.
  175. Updated on successful return
  176. OutputBuffer - pointer to buffer where next element is copied
  177. OutputBufferLength - size of OutputBuffer (in bytes)
  178. BlankIsDelimiter - TRUE indicates blank should be considered a delimiter
  179. character.
  180. Return Value:
  181. ULONG
  182. -1 = error - extracted element breaks OutputBuffer
  183. 0 = no element extracted (buffer is empty or all
  184. delimiters)
  185. 1..OutputBufferLength = OutputBuffer contains extracted element
  186. --*/
  187. {
  188. ULONG elementLength = 0;
  189. ULONG inputLength = *InputBufferLength;
  190. PWSTR input = *InputBuffer;
  191. while (IS_DELIMITER(*input, BlankIsDelimiter) && inputLength) {
  192. ++input;
  193. inputLength -= sizeof(*input);
  194. }
  195. while (!IS_DELIMITER(*input, BlankIsDelimiter) && inputLength) {
  196. if (!OutputBufferLength) {
  197. return (ULONG)-1L;
  198. }
  199. *OutputBuffer++ = *input++;
  200. OutputBufferLength -= sizeof(*input);
  201. elementLength += sizeof(*input);
  202. inputLength -= sizeof(*input);
  203. }
  204. *InputBuffer = input;
  205. *InputBufferLength = inputLength;
  206. return elementLength;
  207. }
  208. //
  209. // Illegal names characters same as those in net\api. Move to common
  210. // include directory
  211. //
  212. #define ILLEGAL_NAME_CHARS L"\001\002\003\004\005\006\007" \
  213. L"\010\011\012\013\014\015\016\017" \
  214. L"\020\021\022\023\024\025\026\027" \
  215. L"\030\031\032\033\034\035\036\037" \
  216. L"\"/\\[]:|<>+=;,?*"
  217. static
  218. BOOLEAN
  219. ValidateName(
  220. IN PWSTR Name,
  221. IN ULONG Length
  222. )
  223. /*++
  224. Routine Description:
  225. Determines whether a computer name is valid or not
  226. Arguments:
  227. Name - pointer to zero terminated wide-character computer name
  228. Length - of Name in characters, excluding zero-terminator
  229. Return Value:
  230. BOOLEAN
  231. TRUE Name is valid computer name
  232. FALSE Name is not valid computer name
  233. --*/
  234. {
  235. if (Length > MAX_COMPUTERNAME_LENGTH || Length < 1) {
  236. return FALSE;
  237. }
  238. //
  239. // Don't allow leading or trailing blanks in the computername.
  240. //
  241. if ( Name[0] == ' ' || Name[Length-1] == ' ' ) {
  242. return(FALSE);
  243. }
  244. return (BOOLEAN)((ULONG)wcscspn(Name, ILLEGAL_NAME_CHARS) == Length);
  245. }