Leaked source code of windows server 2003
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.

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