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.

1743 lines
43 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <lmcons.h>
  6. #include <lmerr.h>
  7. #include <align.h>
  8. #include <netdebug.h>
  9. #include <lmapibuf.h>
  10. #define DEBUG_ALLOCATE
  11. #include <nldebug.h>
  12. #undef DEBUG_ALLOCATE
  13. #ifndef SECURITY_WIN32
  14. #define SECURITY_WIN32
  15. #endif // SECURITY_WIN32
  16. #include <security.h>
  17. #include "ntcalls.h"
  18. #include <icanon.h>
  19. #include <tstring.h>
  20. #define _DECL_DLLMAIN
  21. BOOL WINAPI DllMain(
  22. HANDLE hInstance,
  23. ULONG dwReason,
  24. PVOID lpReserved
  25. )
  26. {
  27. NET_API_STATUS Status = NO_ERROR;
  28. if (dwReason == DLL_PROCESS_ATTACH)
  29. {
  30. Status = DCNameInitialize();
  31. #if NETLOGONDBG
  32. NlGlobalTrace = 0xFFFFFFFF;
  33. #endif // NETLOGONDBG
  34. if (Status != NO_ERROR)
  35. {
  36. return FALSE;
  37. }
  38. }
  39. else if (dwReason == DLL_PROCESS_DETACH)
  40. {
  41. DCNameClose();
  42. }
  43. return TRUE;
  44. }
  45. VOID
  46. NetpAssertFailed(
  47. IN LPDEBUG_STRING FailedAssertion,
  48. IN LPDEBUG_STRING FileName,
  49. IN DWORD LineNumber,
  50. IN LPDEBUG_STRING Message OPTIONAL
  51. )
  52. {
  53. assert(FALSE);
  54. }
  55. VOID
  56. NlAssertFailed(
  57. IN PVOID FailedAssertion,
  58. IN PVOID FileName,
  59. IN ULONG LineNumber,
  60. IN PCHAR Message OPTIONAL
  61. )
  62. {
  63. assert(FALSE);
  64. }
  65. VOID
  66. MyRtlAssert(
  67. IN PVOID FailedAssertion,
  68. IN PVOID FileName,
  69. IN ULONG LineNumber,
  70. IN PCHAR Message OPTIONAL
  71. )
  72. {
  73. assert(FALSE);
  74. }
  75. /****************************************************************************/
  76. NET_API_STATUS
  77. NetpGetComputerName (
  78. OUT LPWSTR *ComputerNamePtr
  79. )
  80. /*++
  81. Routine Description:
  82. This routine obtains the computer name from a persistent database.
  83. Currently that database is the NT.CFG file.
  84. This routine makes no assumptions on the length of the computername.
  85. Therefore, it allocates the storage for the name using NetApiBufferAllocate.
  86. It is necessary for the user to free that space using NetApiBufferFree when
  87. finished.
  88. Arguments:
  89. ComputerNamePtr - This is a pointer to the location where the pointer
  90. to the computer name is to be placed.
  91. Return Value:
  92. NERR_Success - If the operation was successful.
  93. It will return assorted Net or Win32 error messages if not.
  94. --*/
  95. {
  96. NET_API_STATUS ApiStatus = NO_ERROR;
  97. ULONG Index;
  98. DWORD NameSize = MAX_COMPUTERNAME_LENGTH + 1; // updated by win32 API.
  99. CHAR AnsiName[MAX_COMPUTERNAME_LENGTH + 1];
  100. //
  101. // Check for caller's errors.
  102. //
  103. if (ComputerNamePtr == NULL) {
  104. ApiStatus = ERROR_INVALID_PARAMETER;
  105. goto Cleanup;
  106. }
  107. //
  108. // Allocate space for computer name.
  109. //
  110. *ComputerNamePtr = (LPWSTR)LocalAlloc( 0,
  111. (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR) );
  112. if (*ComputerNamePtr == NULL) {
  113. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  114. goto Cleanup;
  115. }
  116. //
  117. // Ask system what current computer name is.
  118. //
  119. if ( !GetComputerName(
  120. AnsiName,
  121. &NameSize ) ) {
  122. ApiStatus = (NET_API_STATUS) GetLastError();
  123. goto Cleanup;
  124. }
  125. Index = MultiByteToWideChar(
  126. CP_ACP,
  127. MB_PRECOMPOSED,
  128. AnsiName,
  129. NameSize,
  130. *ComputerNamePtr,
  131. (MAX_COMPUTERNAME_LENGTH) * sizeof(WCHAR)
  132. );
  133. if (!Index)
  134. {
  135. ApiStatus = GetLastError();
  136. goto Cleanup;
  137. }
  138. *(*ComputerNamePtr + Index) = UNICODE_NULL;
  139. //
  140. // All done.
  141. //
  142. Cleanup:
  143. if (ApiStatus != NO_ERROR)
  144. {
  145. if (ComputerNamePtr)
  146. {
  147. if (*ComputerNamePtr)
  148. {
  149. LocalFree( *ComputerNamePtr );
  150. *ComputerNamePtr = NULL;
  151. }
  152. }
  153. }
  154. return ApiStatus;
  155. }
  156. VOID
  157. MyRtlInitUnicodeString(
  158. OUT PUNICODE_STRING DestinationString,
  159. IN PCWSTR SourceString OPTIONAL
  160. )
  161. /*++
  162. Routine Description:
  163. The RtlInitUnicodeString function initializes an NT counted
  164. unicode string. The DestinationString is initialized to point to
  165. the SourceString and the Length and MaximumLength fields of
  166. DestinationString are initialized to the length of the SourceString,
  167. which is zero if SourceString is not specified.
  168. Arguments:
  169. DestinationString - Pointer to the counted string to initialize
  170. SourceString - Optional pointer to a null terminated unicode string that
  171. the counted string is to point to.
  172. Return Value:
  173. None.
  174. --*/
  175. {
  176. ULONG Length;
  177. DestinationString->Buffer = (PWSTR)SourceString;
  178. if (ARGUMENT_PRESENT( SourceString )) {
  179. Length = wcslen( SourceString ) * sizeof( WCHAR );
  180. DestinationString->Length = (USHORT)Length;
  181. DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
  182. }
  183. else {
  184. DestinationString->MaximumLength = 0;
  185. DestinationString->Length = 0;
  186. }
  187. }
  188. VOID
  189. MyRtlInitString(
  190. OUT PSTRING DestinationString,
  191. IN PCSTR SourceString OPTIONAL
  192. )
  193. /*++
  194. Routine Description:
  195. The RtlInitString function initializes an NT counted string.
  196. The DestinationString is initialized to point to the SourceString
  197. and the Length and MaximumLength fields of DestinationString are
  198. initialized to the length of the SourceString, which is zero if
  199. SourceString is not specified.
  200. Arguments:
  201. DestinationString - Pointer to the counted string to initialize
  202. SourceString - Optional pointer to a null terminated string that
  203. the counted string is to point to.
  204. Return Value:
  205. None.
  206. --*/
  207. {
  208. ULONG Length;
  209. DestinationString->Buffer = (PCHAR)SourceString;
  210. if (ARGUMENT_PRESENT( SourceString )) {
  211. Length = strlen(SourceString);
  212. DestinationString->Length = (USHORT)Length;
  213. DestinationString->MaximumLength = (USHORT)(Length+1);
  214. }
  215. }
  216. // from net\netlib\memalloc.c
  217. // Define memory alloc/realloc flags. We are NOT using movable or zeroed
  218. // on allocation here.
  219. #define NETLIB_LOCAL_ALLOCATION_FLAGS LMEM_FIXED
  220. LPVOID
  221. NetpMemoryAllocate(
  222. IN DWORD Size
  223. )
  224. /*++
  225. Routine Description:
  226. NetpMemoryAllocate will allocate memory, or return NULL if not available.
  227. Arguments:
  228. Size - Supplies number of bytes of memory to allocate.
  229. Return Value:
  230. LPVOID - pointer to allocated memory.
  231. NULL - no memory is available.
  232. --*/
  233. {
  234. LPVOID NewAddress;
  235. if (Size == 0) {
  236. return (NULL);
  237. }
  238. #ifdef WIN32
  239. {
  240. HANDLE hMem;
  241. hMem = LocalAlloc(
  242. NETLIB_LOCAL_ALLOCATION_FLAGS,
  243. Size); // size in bytes
  244. NewAddress = (LPVOID) hMem;
  245. }
  246. #else // ndef WIN32
  247. #ifndef CDEBUG
  248. NewAddress = RtlAllocateHeap(
  249. RtlProcessHeap( ), 0, // heap handle
  250. Size )); // bytes wanted
  251. #else // def CDEBUG
  252. NetpAssert( Size == (DWORD) (size_t) Size );
  253. NewAddress = malloc( (size_t) Size ));
  254. #endif // def CDEBUG
  255. #endif // ndef WIN32
  256. NetpAssert( ROUND_UP_POINTER( NewAddress, ALIGN_WORST) == NewAddress);
  257. return (NewAddress);
  258. } // NetpMemoryAllocate
  259. VOID
  260. NetpMemoryFree(
  261. IN LPVOID Address OPTIONAL
  262. )
  263. /*++
  264. Routine Description:
  265. Free memory at Address (must have been gotten from NetpMemoryAllocate or
  266. NetpMemoryReallocate). (Address may be NULL.)
  267. Arguments:
  268. Address - points to an area allocated by NetpMemoryAllocate (or
  269. NetpMemoryReallocate).
  270. Return Value:
  271. None.
  272. --*/
  273. {
  274. NetpAssert( ROUND_UP_POINTER( Address, ALIGN_WORST) == Address);
  275. #ifdef WIN32
  276. if (Address == NULL) {
  277. return;
  278. }
  279. if (LocalFree(Address) != NULL) {
  280. NetpAssert(FALSE);
  281. }
  282. #else // ndef WIN32
  283. #ifndef CDEBUG
  284. if (Address == NULL) {
  285. return;
  286. }
  287. RtlFreeHeap(
  288. RtlProcessHeap( ), 0, // heap handle
  289. Address); // addr of alloc'ed space.
  290. #else // def CDEBUG
  291. free( Address );
  292. #endif // def CDEBUG
  293. #endif // ndef WIN32
  294. } // netpMemoryFree
  295. /*
  296. ULONG
  297. MyRtlxOemStringToUnicodeSize(
  298. POEM_STRING OemString
  299. )
  300. {
  301. return ((OemString->Length + sizeof((UCHAR)NULL)) * sizeof(WCHAR));
  302. }
  303. ULONG
  304. RtlxUnicodeStringToOemSize(
  305. PUNICODE_STRING UnicodeString
  306. )
  307. {
  308. return ((UnicodeString->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR));
  309. }
  310. */
  311. // from net\netlib\copystr.c
  312. VOID
  313. NetpCopyWStrToStr(
  314. OUT LPSTR Dest,
  315. IN LPWSTR Src
  316. )
  317. /*++
  318. Routine Description:
  319. NetpCopyWStrToStr copies characters from a source string
  320. to a destination, converting as it copies them.
  321. Arguments:
  322. Dest - is an LPSTR indicating where the converted characters are to go.
  323. This string will be in the default codepage for the LAN.
  324. Src - is in LPWSTR indicating the source string.
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. OEM_STRING DestAnsi;
  330. NTSTATUS NtStatus;
  331. UNICODE_STRING SrcUnicode;
  332. NetpAssert( Dest != NULL );
  333. NetpAssert( Src != NULL );
  334. NetpAssert( ((LPVOID)Dest) != ((LPVOID)Src) );
  335. NetpAssert( ROUND_UP_POINTER( Src, ALIGN_WCHAR ) == Src );
  336. *Dest = '\0';
  337. RtlInitString(
  338. & DestAnsi, // output: struct
  339. Dest); // input: null terminated
  340. // Tell RTL routines there's enough memory out there.
  341. DestAnsi.MaximumLength = (USHORT) (wcslen(Src)+1);
  342. RtlInitUnicodeString(
  343. & SrcUnicode, // output: struct
  344. Src); // input: null terminated
  345. NtStatus = RtlUnicodeStringToOemString(
  346. & DestAnsi, // output: struct
  347. & SrcUnicode, // input: struct
  348. (BOOLEAN) FALSE); // don't allocate string.
  349. NetpAssert( NT_SUCCESS(NtStatus) );
  350. } // NetpCopyWStrToStr
  351. // from net\netlib\copystr.c
  352. VOID
  353. NetpCopyStrToWStr(
  354. OUT LPWSTR Dest,
  355. IN LPSTR Src
  356. )
  357. /*++
  358. Routine Description:
  359. NetpCopyStrToWStr copies characters from a source string
  360. to a destination, converting as it copies them.
  361. Arguments:
  362. Dest - is an LPWSTR indicating where the converted characters are to go.
  363. Src - is in LPSTR indicating the source string. This must be a string in
  364. the default codepage of the LAN.
  365. Return Value:
  366. None.
  367. --*/
  368. {
  369. UNICODE_STRING DestUnicode;
  370. NTSTATUS NtStatus;
  371. OEM_STRING SrcAnsi;
  372. NetpAssert( Dest != NULL );
  373. NetpAssert( Src != NULL );
  374. NetpAssert( ((LPVOID)Dest) != ((LPVOID)Src) );
  375. NetpAssert( ROUND_UP_POINTER( Dest, ALIGN_WCHAR ) == Dest );
  376. *Dest = L'\0';
  377. RtlInitString(
  378. & SrcAnsi, // output: struct
  379. Src); // input: null terminated
  380. RtlInitUnicodeString(
  381. & DestUnicode, // output: struct
  382. Dest); // input: null terminated
  383. // Tell RTL routines there's enough memory out there.
  384. DestUnicode.MaximumLength = (USHORT)
  385. ((USHORT) (strlen(Src)+1)) * (USHORT) sizeof(wchar_t);
  386. NtStatus = RtlOemStringToUnicodeString(
  387. & DestUnicode, // output: struct
  388. & SrcAnsi, // input: struct
  389. (BOOLEAN) FALSE); // don't allocate string.
  390. NetpAssert( NT_SUCCESS(NtStatus) );
  391. } // NetpCopyStrToWStr
  392. //
  393. // Inline functions to convert between FILETIME and TimeStamp
  394. //
  395. #pragma warning( disable : 4035) // Don't complain about no return
  396. TimeStamp __inline
  397. FileTimeToTimeStamp(
  398. const FILETIME *pft)
  399. {
  400. _asm {
  401. mov edx, pft
  402. mov eax, [edx].dwLowDateTime
  403. mov edx, [edx].dwHighDateTime
  404. }
  405. }
  406. #pragma warning( default : 4035) // Reenable warning
  407. NTSTATUS
  408. MyNtQuerySystemTime (
  409. OUT PTimeStamp SystemTimeStamp
  410. )
  411. /*++
  412. Routine Description:
  413. This routine returns the current system time (UTC), as a timestamp
  414. (a 64-bit unsigned integer, in 100-nanosecond increments).
  415. Arguments:
  416. None.
  417. Return Value:
  418. The current system time.
  419. --*/
  420. {
  421. SYSTEMTIME SystemTime;
  422. FILETIME FileTime;
  423. GetSystemTime(&SystemTime);
  424. SystemTimeToFileTime(&SystemTime, &FileTime);
  425. *SystemTimeStamp = FileTimeToTimeStamp(&FileTime);
  426. return STATUS_SUCCESS; // WIN32_CHICAGO do something useful here
  427. }
  428. ULONG
  429. MyUnicodeStringToMultibyteSize(
  430. IN PUNICODE_STRING UnicodeString,
  431. IN UINT CodePage
  432. )
  433. /*++
  434. Routine Description:
  435. This function computes the number of bytes required to store
  436. a NULL terminated oem/ansi string that is equivalent to the specified
  437. unicode string. If an oem/ansi string can not be formed or the specified
  438. unicode string is empty, the return value is 0.
  439. Arguments:
  440. UnicodeString - Supplies a unicode string whose equivalent size as
  441. an oem string is to be calculated.
  442. CodePage - Specifies the code page used to perform the conversion.
  443. Return Value:
  444. 0 - The operation failed, the unicode string can not be translated
  445. into oem/ansi using the OEM/ANSI code page therefore no storage is
  446. needed for the oem/ansi string.
  447. !0 - The operation was successful. The return value specifies the
  448. number of bytes required to hold an NULL terminated oem/ansi string
  449. equivalent to the specified unicode string.
  450. --*/
  451. {
  452. int cbMultiByteString = 0;
  453. if (UnicodeString->Length != 0) {
  454. cbMultiByteString = WideCharToMultiByte(
  455. CodePage,
  456. 0, // WIN32_CHICAGO this is something else
  457. UnicodeString->Buffer,
  458. UnicodeString->Length / sizeof (WCHAR),
  459. NULL,
  460. 0,
  461. NULL,
  462. NULL );
  463. }
  464. if ( cbMultiByteString > 0 ) {
  465. //
  466. // Add one byte for the NULL terminating character
  467. //
  468. return (ULONG) (cbMultiByteString + 1);
  469. } else {
  470. return 0;
  471. }
  472. }
  473. ULONG
  474. MyMultibyteStringToUnicodeSize(
  475. IN PSTRING MultibyteString,
  476. IN UINT CodePage
  477. )
  478. /*++
  479. Routine Description:
  480. This function computes the number of bytes required to store
  481. a NULL terminated unicode string that is equivalent to the specified
  482. oem/ansi string. If a unicode string can not be formed or the specified
  483. ansi/oem string is empty, the return value is 0.
  484. Arguments:
  485. UnicodeString - Supplies a unicode string whose equivalent size as
  486. an oem string is to be calculated.
  487. CodePage - Specifies the code page used to perform the conversion.
  488. Return Value:
  489. 0 - The operation failed, the oem/ansi string can not be translated
  490. into unicode using the OEM/ANSI code page therefore no storage is
  491. needed for the unicode string.
  492. !0 - The operation was successful. The return value specifies the
  493. number of bytes required to hold an NULL terminated unicode string
  494. equivalent to the specified oem/ansi string.
  495. --*/
  496. {
  497. int ccUnicodeString = 0;
  498. if (MultibyteString->Length != 0) {
  499. ccUnicodeString = MultiByteToWideChar(
  500. CodePage,
  501. MB_PRECOMPOSED,
  502. MultibyteString->Buffer,
  503. MultibyteString->Length,
  504. NULL,
  505. 0 );
  506. }
  507. if ( ccUnicodeString > 0 ) {
  508. //
  509. // Add the NULL terminating character
  510. //
  511. return (ULONG) ((ccUnicodeString + 1) * sizeof(WCHAR));
  512. } else {
  513. return 0;
  514. }
  515. }
  516. NTSTATUS
  517. MyRtlOemStringToUnicodeString(
  518. OUT PUNICODE_STRING DestinationString,
  519. IN POEM_STRING SourceString,
  520. IN BOOLEAN AllocateDestinationString
  521. )
  522. /*++
  523. Routine Description:
  524. This functions converts the specified oem source string into a
  525. Unicode string. The translation is done with respect to the
  526. current system locale information.
  527. Arguments:
  528. DestinationString - Returns a unicode string that is equivalent to
  529. the oem source string. The maximum length field is only
  530. set if AllocateDestinationString is TRUE.
  531. SourceString - Supplies the oem source string that is to be
  532. converted to unicode.
  533. AllocateDestinationString - Supplies a flag that controls whether or
  534. not this API allocates the buffer space for the destination
  535. string. If it does, then the buffer must be deallocated using
  536. RtlFreeUnicodeString (note that only storage for
  537. DestinationString->Buffer is allocated by this API).
  538. Return Value:
  539. SUCCESS - The conversion was successful
  540. !SUCCESS - The operation failed. No storage was allocated and no
  541. conversion was done. None.
  542. --*/
  543. {
  544. ULONG UnicodeLength;
  545. ULONG Index = 0;
  546. NTSTATUS st = STATUS_SUCCESS;
  547. UnicodeLength = MyMultibyteStringToUnicodeSize( SourceString, CP_OEMCP );
  548. if ( UnicodeLength > MAXUSHORT || UnicodeLength == 0 ) {
  549. return STATUS_INVALID_PARAMETER_2;
  550. }
  551. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  552. if ( AllocateDestinationString ) {
  553. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  554. DestinationString->Buffer = (PWSTR) LocalAlloc(0, UnicodeLength);
  555. if ( !DestinationString->Buffer ) {
  556. return STATUS_NO_MEMORY;
  557. }
  558. }
  559. else {
  560. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  561. return STATUS_BUFFER_OVERFLOW;
  562. }
  563. }
  564. if (SourceString->Length != 0)
  565. {
  566. Index = MultiByteToWideChar(
  567. CP_OEMCP,
  568. MB_PRECOMPOSED,
  569. SourceString->Buffer,
  570. SourceString->Length,
  571. DestinationString->Buffer,
  572. DestinationString->MaximumLength
  573. );
  574. if (Index == 0) {
  575. if ( AllocateDestinationString ) {
  576. LocalFree(DestinationString->Buffer);
  577. }
  578. return STATUS_NO_MEMORY;
  579. }
  580. }
  581. DestinationString->Buffer[Index] = UNICODE_NULL;
  582. return st;
  583. }
  584. NTSTATUS
  585. MyRtlUnicodeStringToOemString(
  586. OUT POEM_STRING DestinationString,
  587. IN PUNICODE_STRING SourceString,
  588. IN BOOLEAN AllocateDestinationString
  589. )
  590. /*++
  591. Routine Description:
  592. This functions converts the specified unicode source string into an
  593. oem string. The translation is done with respect to the
  594. current system locale information.
  595. Arguments:
  596. DestinationString - Returns an oem string that is equivalent to the
  597. unicode source string. If the translation can not be done,
  598. an error is returned. The maximum length field is only set if
  599. AllocateDestinationString is TRUE.
  600. SourceString - Supplies the unicode source string that is to be
  601. converted to oem.
  602. AllocateDestinationString - Supplies a flag that controls whether or
  603. not this API allocates the buffer space for the destination
  604. string. If it does, then the buffer must be deallocated using
  605. RtlFreeAnsiString (note that only storage for
  606. DestinationString->Buffer is allocated by this API).
  607. Return Value:
  608. SUCCESS - The conversion was successful
  609. !SUCCESS - The operation failed. No storage was allocated and no
  610. conversion was done. None.
  611. --*/
  612. {
  613. ULONG OemLength;
  614. ULONG Index = 0;
  615. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  616. BOOL fUsed;
  617. OemLength = MyUnicodeStringToMultibyteSize( SourceString, CP_OEMCP );
  618. if ( OemLength > MAXUSHORT || OemLength == 0 ) {
  619. return STATUS_INVALID_PARAMETER_2;
  620. }
  621. DestinationString->Length = (USHORT)(OemLength - 1);
  622. if ( AllocateDestinationString ) {
  623. DestinationString->MaximumLength = (USHORT)OemLength;
  624. DestinationString->Buffer = (LPSTR)LocalAlloc(0, OemLength);
  625. if ( !DestinationString->Buffer ) {
  626. return STATUS_NO_MEMORY;
  627. }
  628. }
  629. else {
  630. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  631. /*
  632. * Return STATUS_BUFFER_OVERFLOW, but translate as much as
  633. * will fit into the buffer first. This is the expected
  634. * behavior for routines such as GetProfileStringA.
  635. * Set the length of the buffer to one less than the maximum
  636. * (so that the trail byte of a double byte char is not
  637. * overwritten by doing DestinationString->Buffer[Index] = '\0').
  638. * RtlUnicodeToMultiByteN is careful not to truncate a
  639. * multibyte character.
  640. */
  641. if (!DestinationString->MaximumLength) {
  642. return STATUS_BUFFER_OVERFLOW;
  643. }
  644. ReturnStatus = STATUS_BUFFER_OVERFLOW;
  645. DestinationString->Length = DestinationString->MaximumLength - 1;
  646. }
  647. }
  648. if (SourceString->Length != 0)
  649. {
  650. Index = WideCharToMultiByte(
  651. CP_OEMCP,
  652. 0, // WIN32_CHICAGO this is something else
  653. SourceString->Buffer,
  654. SourceString->Length / sizeof (WCHAR),
  655. DestinationString->Buffer,
  656. DestinationString->MaximumLength,
  657. NULL,
  658. &fUsed
  659. );
  660. if (Index == 0)
  661. { // WIN32_CHICAGO do something useful here
  662. if ( AllocateDestinationString ) {
  663. LocalFree(DestinationString->Buffer);
  664. }
  665. return STATUS_NO_MEMORY;
  666. }
  667. }
  668. DestinationString->Buffer[Index] = '\0';
  669. return ReturnStatus;
  670. }
  671. NTSTATUS
  672. MyRtlUnicodeStringToAnsiString(
  673. OUT PANSI_STRING DestinationString,
  674. IN PUNICODE_STRING SourceString,
  675. IN BOOLEAN AllocateDestinationString
  676. )
  677. /*++
  678. Routine Description:
  679. This functions converts the specified unicode source string into an
  680. ansi string. The translation is done with respect to the
  681. current system locale information.
  682. Arguments:
  683. DestinationString - Returns an ansi string that is equivalent to the
  684. unicode source string. If the translation can not be done,
  685. an error is returned. The maximum length field is only set if
  686. AllocateDestinationString is TRUE.
  687. SourceString - Supplies the unicode source string that is to be
  688. converted to ansi.
  689. AllocateDestinationString - Supplies a flag that controls whether or
  690. not this API allocates the buffer space for the destination
  691. string. If it does, then the buffer must be deallocated using
  692. RtlFreeAnsiString (note that only storage for
  693. DestinationString->Buffer is allocated by this API).
  694. Return Value:
  695. SUCCESS - The conversion was successful
  696. !SUCCESS - The operation failed. No storage was allocated and no
  697. conversion was done. None.
  698. --*/
  699. {
  700. ULONG AnsiLength;
  701. ULONG Index = 0;
  702. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  703. BOOL fUsed;
  704. AnsiLength = MyUnicodeStringToMultibyteSize( SourceString, CP_ACP );
  705. if ( AnsiLength > MAXUSHORT || AnsiLength == 0 ) {
  706. return STATUS_INVALID_PARAMETER_2;
  707. }
  708. DestinationString->Length = (USHORT)(AnsiLength - 1);
  709. if ( AllocateDestinationString ) {
  710. DestinationString->MaximumLength = (USHORT)AnsiLength;
  711. DestinationString->Buffer = (LPSTR)LocalAlloc(0, AnsiLength);
  712. if ( !DestinationString->Buffer ) {
  713. return STATUS_NO_MEMORY;
  714. }
  715. }
  716. else {
  717. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  718. /*
  719. * Return STATUS_BUFFER_OVERFLOW, but translate as much as
  720. * will fit into the buffer first. This is the expected
  721. * behavior for routines such as GetProfileStringA.
  722. * Set the length of the buffer to one less than the maximum
  723. * (so that the trail byte of a double byte char is not
  724. * overwritten by doing DestinationString->Buffer[Index] = '\0').
  725. * RtlUnicodeToMultiByteN is careful not to truncate a
  726. * multibyte character.
  727. */
  728. if (!DestinationString->MaximumLength) {
  729. return STATUS_BUFFER_OVERFLOW;
  730. }
  731. ReturnStatus = STATUS_BUFFER_OVERFLOW;
  732. DestinationString->Length = DestinationString->MaximumLength - 1;
  733. }
  734. }
  735. if (SourceString->Length != 0)
  736. {
  737. Index = WideCharToMultiByte(
  738. CP_ACP,
  739. 0, // WIN32_CHICAGO this is something else
  740. SourceString->Buffer,
  741. SourceString->Length / sizeof (WCHAR),
  742. DestinationString->Buffer,
  743. DestinationString->MaximumLength,
  744. NULL,
  745. &fUsed
  746. );
  747. if (Index == 0)
  748. { // WIN32_CHICAGO do something useful here
  749. if ( AllocateDestinationString ) {
  750. LocalFree(DestinationString->Buffer);
  751. }
  752. return STATUS_NO_MEMORY;
  753. }
  754. }
  755. DestinationString->Buffer[Index] = '\0';
  756. return ReturnStatus;
  757. }
  758. NTSTATUS
  759. MyRtlAnsiStringToUnicodeString(
  760. OUT PUNICODE_STRING DestinationString,
  761. IN PANSI_STRING SourceString,
  762. IN BOOLEAN AllocateDestinationString
  763. )
  764. /*++
  765. Routine Description:
  766. This functions converts the specified ansi source string into a
  767. Unicode string. The translation is done with respect to the
  768. current system locale information.
  769. Arguments:
  770. DestinationString - Returns a unicode string that is equivalent to
  771. the ansi source string. The maximum length field is only
  772. set if AllocateDestinationString is TRUE.
  773. SourceString - Supplies the ansi source string that is to be
  774. converted to unicode.
  775. AllocateDestinationString - Supplies a flag that controls whether or
  776. not this API allocates the buffer space for the destination
  777. string. If it does, then the buffer must be deallocated using
  778. RtlFreeUnicodeString (note that only storage for
  779. DestinationString->Buffer is allocated by this API).
  780. Return Value:
  781. SUCCESS - The conversion was successful
  782. !SUCCESS - The operation failed. No storage was allocated and no
  783. conversion was done. None.
  784. --*/
  785. {
  786. ULONG UnicodeLength;
  787. ULONG Index = 0;
  788. NTSTATUS st = STATUS_SUCCESS;
  789. UnicodeLength = MyMultibyteStringToUnicodeSize( SourceString, CP_ACP );
  790. if ( UnicodeLength > MAXUSHORT || UnicodeLength == 0 ) {
  791. return STATUS_INVALID_PARAMETER_2;
  792. }
  793. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  794. if ( AllocateDestinationString ) {
  795. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  796. DestinationString->Buffer = (PWSTR) LocalAlloc(0, UnicodeLength);
  797. if ( !DestinationString->Buffer ) {
  798. return STATUS_NO_MEMORY;
  799. }
  800. }
  801. else {
  802. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  803. return STATUS_BUFFER_OVERFLOW;
  804. }
  805. }
  806. if (SourceString->Length != 0)
  807. {
  808. Index = MultiByteToWideChar(
  809. CP_ACP,
  810. MB_PRECOMPOSED,
  811. SourceString->Buffer,
  812. SourceString->Length,
  813. DestinationString->Buffer,
  814. DestinationString->MaximumLength
  815. );
  816. if (Index == 0) {
  817. if ( AllocateDestinationString ) {
  818. LocalFree(DestinationString->Buffer);
  819. }
  820. return STATUS_NO_MEMORY;
  821. }
  822. }
  823. DestinationString->Buffer[Index] = UNICODE_NULL;
  824. return st;
  825. }
  826. // from ntos\rtl\random.c
  827. #define Multiplier ((ULONG)(0x80000000ul - 19)) // 2**31 - 19
  828. #define Increment ((ULONG)(0x80000000ul - 61)) // 2**31 - 61
  829. #define Modulus ((ULONG)(0x80000000ul - 1)) // 2**31 - 1
  830. ULONG
  831. MyRtlUniform (
  832. IN OUT PULONG Seed
  833. )
  834. /*++
  835. Routine Description:
  836. A simple uniform random number generator, based on D.H. Lehmer's 1948
  837. alrogithm.
  838. Arguments:
  839. Seed - Supplies a pointer to the random number generator seed.
  840. Return Value:
  841. ULONG - returns a random number uniformly distributed over [0..MAXLONG]
  842. --*/
  843. {
  844. *Seed = ((Multiplier * (*Seed)) + Increment) % Modulus;
  845. return *Seed;
  846. }
  847. // from net\netlib\allocstr.c
  848. LPSTR
  849. NetpAllocAStrFromWStr (
  850. IN LPCWSTR Unicode
  851. )
  852. /*++
  853. Routine Description:
  854. Convert an UNICODE (zero terminated) string to the corresponding ASCII
  855. string.
  856. Arguments:
  857. Unicode - Specifies the UNICODE zero terminated string to convert.
  858. Return Value:
  859. NULL - There was some error in the conversion.
  860. Otherwise, it returns a pointer to the zero terminated ASCII string in
  861. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  862. --*/
  863. {
  864. OEM_STRING AnsiString = {0};
  865. UNICODE_STRING UnicodeString;
  866. RtlInitUnicodeString( &UnicodeString, Unicode );
  867. if(!NT_SUCCESS( RtlUnicodeStringToAnsiString( &AnsiString,
  868. &UnicodeString,
  869. TRUE))){
  870. return NULL;
  871. }
  872. return AnsiString.Buffer;
  873. } // NetpAllocAStrFromWStr
  874. // from net\netlib\allocstr.c
  875. LPWSTR
  876. NetpAllocWStrFromAStr(
  877. IN LPCSTR Ansi
  878. )
  879. /*++
  880. Routine Description:
  881. Convert an ASCII (zero terminated) string to the corresponding UNICODE
  882. string.
  883. Arguments:
  884. Ansi - Specifies the ASCII zero terminated string to convert.
  885. Return Value:
  886. NULL - There was some error in the conversion.
  887. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  888. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  889. --*/
  890. {
  891. OEM_STRING AnsiString;
  892. UNICODE_STRING UnicodeString = {0};
  893. RtlInitString( &AnsiString, Ansi );
  894. if(!NT_SUCCESS( RtlAnsiStringToUnicodeString( &UnicodeString,
  895. &AnsiString,
  896. TRUE))){
  897. return NULL;
  898. }
  899. return UnicodeString.Buffer;
  900. } // NetpAllocWStrFromAStr
  901. LPWSTR
  902. NetpAllocWStrFromOemStr(
  903. IN LPCSTR Oem
  904. )
  905. /*++
  906. Routine Description:
  907. Convert an OEM (zero terminated) string to the corresponding UNICODE
  908. string.
  909. Arguments:
  910. Oem - Specifies the OEM zero terminated string to convert.
  911. Return Value:
  912. NULL - There was some error in the conversion.
  913. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  914. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  915. --*/
  916. {
  917. OEM_STRING OemString;
  918. UNICODE_STRING UnicodeString = {0};
  919. RtlInitString( &OemString, Oem );
  920. if(!NT_SUCCESS( RtlOemStringToUnicodeString( &UnicodeString,
  921. &OemString,
  922. TRUE))){
  923. return NULL;
  924. }
  925. return UnicodeString.Buffer;
  926. } // NetpAllocWStrFromOemStr
  927. // from net\netlib\allocstr.c
  928. LPWSTR
  929. NetpAllocWStrFromWStr(
  930. IN LPWSTR Unicode
  931. )
  932. /*++
  933. Routine Description:
  934. Allocate and copy unicode string (wide character strdup)
  935. Arguments:
  936. Unicode - pointer to wide character string to make copy of
  937. Return Value:
  938. NULL - There was some error in the conversion.
  939. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  940. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  941. --*/
  942. {
  943. NET_API_STATUS status;
  944. DWORD size;
  945. LPWSTR ptr;
  946. size = wcslen(Unicode);
  947. size = (size + 1) * sizeof (WCHAR);
  948. status = NetApiBufferAllocate(size, (LPVOID *) (LPVOID) &ptr);
  949. if (status != NO_ERROR) {
  950. return NULL;
  951. }
  952. RtlCopyMemory(ptr, Unicode, size);
  953. return ptr;
  954. } // NetpAllocWStrFromWStr
  955. NET_API_STATUS
  956. NetpGetDomainNameExEx (
  957. OUT LPWSTR *DomainNamePtr,
  958. OUT LPWSTR *DnsDomainNamePtr OPTIONAL,
  959. OUT PBOOLEAN IsworkgroupName
  960. )
  961. {
  962. NET_API_STATUS NetStatus = NO_ERROR;
  963. return NetStatus;
  964. }
  965. // from net\api\canonapi.c
  966. NET_API_STATUS
  967. NET_API_FUNCTION
  968. NetpNameCanonicalize(
  969. IN LPWSTR ServerName OPTIONAL,
  970. IN LPWSTR Name,
  971. OUT LPWSTR Outbuf,
  972. IN DWORD OutbufLen,
  973. IN DWORD NameType,
  974. IN DWORD Flags
  975. )
  976. /*++
  977. Routine Description:
  978. Canonicalizes a name
  979. Arguments:
  980. ServerName - where to run this API
  981. Name - name to canonicalize
  982. Outbuf - where to put canonicalized name
  983. OutbufLen - length of Outbuf
  984. NameType - type of name to canonicalize
  985. Flags - control flags
  986. Return Value:
  987. NET_API_STATUS
  988. --*/
  989. {
  990. NET_API_STATUS status = 0;
  991. DWORD location;
  992. WCHAR serverName[MAX_PATH];
  993. DWORD val;
  994. WCHAR ch;
  995. //
  996. // validate parameters
  997. //
  998. try {
  999. if (ARGUMENT_PRESENT(ServerName)) {
  1000. // val = STRLEN(ServerName);
  1001. val = wcslen(ServerName);
  1002. }
  1003. if (ARGUMENT_PRESENT(Name)) {
  1004. // val = STRLEN(Name);
  1005. val = wcslen(Name);
  1006. }
  1007. if (ARGUMENT_PRESENT(Outbuf)) {
  1008. ch = (volatile WCHAR)*Outbuf;
  1009. *Outbuf = ch;
  1010. ch = (volatile WCHAR)*(Outbuf + OutbufLen/sizeof(*Outbuf) - sizeof(*Outbuf));
  1011. *(Outbuf + OutbufLen/sizeof(*Outbuf) - sizeof(*Outbuf)) = ch;
  1012. } else {
  1013. status = ERROR_INVALID_PARAMETER;
  1014. }
  1015. } except(EXCEPTION_EXECUTE_HANDLER) {
  1016. status = ERROR_INVALID_PARAMETER;
  1017. }
  1018. if (status) {
  1019. return status;
  1020. }
  1021. //
  1022. // call client-side RPC routine or local canonicalization routine
  1023. //
  1024. return NetpwNameCanonicalize(Name, Outbuf, OutbufLen, NameType, Flags);
  1025. // return NetpwNameValidate(Name, NameType, 0);
  1026. }
  1027. // from net\netlib\names.c
  1028. BOOL
  1029. NetpIsDomainNameValid(
  1030. IN LPWSTR DomainName
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. NetpIsDomainNameValid checks for "domain" format.
  1035. The name is only checked syntactically; no attempt is made to determine
  1036. whether or not a domain with that name actually exists.
  1037. Arguments:
  1038. DomainName - Supplies an alleged Domain name.
  1039. Return Value:
  1040. BOOL - TRUE if name is syntactically valid, FALSE otherwise.
  1041. --*/
  1042. {
  1043. NET_API_STATUS ApiStatus = NO_ERROR;
  1044. WCHAR CanonBuf[DNLEN+1];
  1045. if (DomainName == (LPWSTR) NULL) {
  1046. return (FALSE);
  1047. }
  1048. if ( (*DomainName) == TCHAR_EOS ) {
  1049. return (FALSE);
  1050. }
  1051. ApiStatus = NetpNameCanonicalize(
  1052. NULL, // no server name
  1053. DomainName, // name to validate
  1054. CanonBuf, // output buffer
  1055. (DNLEN+1) * sizeof(WCHAR), // output buffer size
  1056. NAMETYPE_DOMAIN, // type
  1057. 0 ); // flags: none
  1058. return (ApiStatus == NO_ERROR);
  1059. } // NetpIsDomainNameValid
  1060. VOID
  1061. MyRtlFreeAnsiString(
  1062. IN OUT PANSI_STRING AnsiString
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This API is used to free storage allocated by
  1067. RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
  1068. is free'd by this routine.
  1069. Arguments:
  1070. AnsiString - Supplies the address of the ansi string whose buffer
  1071. was previously allocated by RtlUnicodeStringToAnsiString.
  1072. Return Value:
  1073. None.
  1074. --*/
  1075. {
  1076. if (AnsiString->Buffer) {
  1077. LocalFree(AnsiString->Buffer);
  1078. ZeroMemory( AnsiString, sizeof( *AnsiString ) );
  1079. }
  1080. }
  1081. VOID
  1082. MyRtlFreeOemString(
  1083. IN OUT POEM_STRING OemString
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This API is used to free storage allocated by
  1088. RtlUnicodeStringToOemString. Note that only OemString->Buffer
  1089. is free'd by this routine.
  1090. Arguments:
  1091. OemString - Supplies the address of the oem string whose buffer
  1092. was previously allocated by RtlUnicodeStringToOemString.
  1093. Return Value:
  1094. None.
  1095. --*/
  1096. {
  1097. if (OemString->Buffer) {
  1098. LocalFree(OemString->Buffer);
  1099. ZeroMemory( OemString, sizeof( *OemString ) );
  1100. }
  1101. }
  1102. VOID
  1103. MyRtlFreeUnicodeString(
  1104. IN OUT PUNICODE_STRING UnicodeString
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. This API is used to free storage allocated by
  1109. RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
  1110. is free'd by this routine.
  1111. Arguments:
  1112. UnicodeString - Supplies the address of the unicode string whose
  1113. buffer was previously allocated by RtlAnsiStringToUnicodeString.
  1114. Return Value:
  1115. None.
  1116. --*/
  1117. {
  1118. if (UnicodeString->Buffer) {
  1119. LocalFree(UnicodeString->Buffer);
  1120. ZeroMemory( UnicodeString, sizeof( *UnicodeString ) );
  1121. }
  1122. }
  1123. DWORD
  1124. MyUniToUpper(WCHAR *dest, WCHAR *src, DWORD len)
  1125. {
  1126. WCHAR *wcp = dest;
  1127. while (*src != L'\0') {
  1128. *wcp++ = towupper(*src);
  1129. src++;
  1130. }
  1131. return(wcp - dest);
  1132. }
  1133. NTSTATUS
  1134. MyRtlUpcaseUnicodeToOemN(
  1135. IN PUNICODE_STRING SourceUnicodeString,
  1136. OUT POEM_STRING DestinationOemString )
  1137. /*++
  1138. Routine Description:
  1139. This functions upper cases the specified unicode source string and
  1140. converts it into an oem string. The translation is done with respect
  1141. to the OEM Code Page (OCP) loaded at boot time. The resulting oem
  1142. string is allocated by this routine and should be deallocated using
  1143. MyRtlFreeOemString.
  1144. This function mimics the behavior of RtlUpcaseUnicodeToOemN. It first
  1145. converts the supplied unicode string into the oem string and then
  1146. converts the oem string back to a unicode string. This is done because
  1147. two different unicode strings may be converted into one oem string, but
  1148. converting back to unicode will create the right unicode string according
  1149. to the OEM Code Page (OCP) loaded at boot time. The resulting unicode
  1150. string is uppercased and then converted to the oem string returned to the
  1151. caller.
  1152. Arguments:
  1153. SourceUnicodeString - Supplies the unicode source string that is to be
  1154. converted to oem.
  1155. DestinationOemString - Returns an oem string that is equivalent to the
  1156. upper case of the unicode source string. If the translation can not
  1157. be done, an error is returned.
  1158. Return Value:
  1159. SUCCESS - The conversion was successful
  1160. Otherwise, an error is returned
  1161. --*/
  1162. {
  1163. NTSTATUS Status;
  1164. OEM_STRING TmpOemString;
  1165. UNICODE_STRING TmpUnicodeString;
  1166. //
  1167. // Initialization
  1168. //
  1169. TmpOemString.Buffer = NULL;
  1170. TmpUnicodeString.Buffer = NULL;
  1171. //
  1172. // First convert the source unicode string into a
  1173. // temprary oem string
  1174. //
  1175. Status = MyRtlUnicodeStringToOemString( &TmpOemString,
  1176. SourceUnicodeString,
  1177. TRUE );
  1178. if ( !NT_SUCCESS(Status) ) {
  1179. goto Cleanup;
  1180. }
  1181. //
  1182. // Then convert the resulting oem string back to unicode
  1183. //
  1184. Status = MyRtlOemStringToUnicodeString( &TmpUnicodeString,
  1185. &TmpOemString,
  1186. TRUE );
  1187. if ( !NT_SUCCESS(Status) ) {
  1188. goto Cleanup;
  1189. }
  1190. //
  1191. // Now uppercase the resulting unicode string in place
  1192. //
  1193. MyUniToUpper( TmpUnicodeString.Buffer, TmpUnicodeString.Buffer, TmpUnicodeString.Length );
  1194. //
  1195. // Finally, convert the unicode string into the resulting oem string
  1196. //
  1197. Status = MyRtlUnicodeStringToOemString( DestinationOemString,
  1198. &TmpUnicodeString,
  1199. TRUE );
  1200. Cleanup:
  1201. MyRtlFreeOemString( &TmpOemString );
  1202. MyRtlFreeUnicodeString( &TmpUnicodeString );
  1203. return Status;
  1204. }
  1205. LPSTR
  1206. MyNetpLogonUnicodeToOem(
  1207. IN LPWSTR Unicode
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. Convert an UNICODE (zero terminated) string to the corresponding
  1212. uppercased oem string.
  1213. Arguments:
  1214. Unicode - Specifies the UNICODE zero terminated string to convert.
  1215. Return Value:
  1216. NULL - There was some error in the conversion.
  1217. Otherwise, it returns a pointer to the zero terminated uppercased
  1218. oem string in an allocated buffer. The buffer can be freed using
  1219. NetpMemoryFree.
  1220. --*/
  1221. {
  1222. OEM_STRING OemString;
  1223. UNICODE_STRING UnicodeString;
  1224. NTSTATUS Status;
  1225. MyRtlInitUnicodeString( &UnicodeString, Unicode );
  1226. Status = MyRtlUpcaseUnicodeToOemN( &UnicodeString, &OemString);
  1227. if( NT_SUCCESS(Status) ) {
  1228. return OemString.Buffer;
  1229. } else {
  1230. return NULL;
  1231. }
  1232. }
  1233. LONG
  1234. NlpChcg_wcsicmp(
  1235. IN LPCWSTR string1,
  1236. IN LPCWSTR string2
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Perform case insensitive, locale independent comparison of two
  1241. unicode strings. This matches the behavior of _wcsicmp that is
  1242. broken on Win9x because it has no unicode support.
  1243. Arguments:
  1244. string1, string2 - Specifies the UNICODE zero terminated strings to compare.
  1245. Return Value:
  1246. 0 if the strings are equal
  1247. -1 if string1 is less than string2
  1248. 1 if string1 is greater than string2
  1249. --*/
  1250. {
  1251. int cc;
  1252. LPSTR AString1 = NULL;
  1253. LPSTR AString2 = NULL;
  1254. AString1 = NetpAllocAStrFromWStr( string1 );
  1255. if ( AString1 == NULL ) {
  1256. cc = ERROR_NOT_ENOUGH_MEMORY;
  1257. goto Cleanup;
  1258. }
  1259. AString2 = NetpAllocAStrFromWStr( string2 );
  1260. if ( AString2 == NULL ) {
  1261. cc = ERROR_NOT_ENOUGH_MEMORY;
  1262. goto Cleanup;
  1263. }
  1264. cc = CompareStringA( 0, // deliberately NOT locale sensitive
  1265. NORM_IGNORECASE | NORM_IGNOREWIDTH | NORM_IGNOREKANATYPE | SORT_STRINGSORT,
  1266. (LPCSTR) AString1, -1,
  1267. (LPCSTR) AString2, -1 );
  1268. Cleanup:
  1269. if ( AString1 != NULL ) {
  1270. NetApiBufferFree( AString1 );
  1271. }
  1272. if ( AString2 != NULL ) {
  1273. NetApiBufferFree( AString2 );
  1274. }
  1275. switch ( cc ) {
  1276. case ERROR_NOT_ENOUGH_MEMORY:
  1277. return ERROR_NOT_ENOUGH_MEMORY;
  1278. case CSTR_EQUAL:
  1279. return 0;
  1280. case CSTR_LESS_THAN:
  1281. return -1;
  1282. case CSTR_GREATER_THAN:
  1283. return 1;
  1284. case 0:
  1285. NlPrint(( NL_CRITICAL, "Cannot CompareStringW: 0x%lx\n", GetLastError() ));
  1286. default:
  1287. return _NLSCMPERROR;
  1288. }
  1289. }