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.

4098 lines
97 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. COMPNAME.C
  5. Abstract:
  6. This module contains the GetComputerName and SetComputerName APIs.
  7. Also: DnsHostnameToComputerName
  8. AddLocalAlternateComputerName
  9. RemoveLocalAlternateComputerName
  10. SetLocalPrimaryComputerName
  11. EnumerateLocalComputerNames
  12. Author:
  13. Dan Hinsley (DanHi) 2-Apr-1992
  14. Revision History:
  15. Greg Johnson (gregjohn) 13-Feb-2001
  16. Notes:
  17. Currently there is no way to enumerate the list of Alternate Netbios
  18. names. Presumably this will be fixed in a future release (Blackcomb?).
  19. The flags parameter to all the *Local* API's is for this use.
  20. --*/
  21. #include <basedll.h>
  22. #include <dnsapi.h>
  23. typedef DNS_STATUS
  24. (WINAPI DNS_VALIDATE_NAME_FN)(
  25. IN LPCWSTR Name,
  26. IN DNS_NAME_FORMAT Format
  27. );
  28. //
  29. //
  30. #define REASONABLE_LENGTH 128
  31. #define COMPUTERNAME_ROOT \
  32. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName"
  33. #define NON_VOLATILE_COMPUTERNAME_NODE \
  34. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
  35. #define VOLATILE_COMPUTERNAME_NODE \
  36. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"
  37. #define ALT_COMPUTERNAME_NODE \
  38. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanServer\\Parameters"
  39. #define VOLATILE_COMPUTERNAME L"ActiveComputerName"
  40. #define NON_VOLATILE_COMPUTERNAME L"ComputerName"
  41. #define COMPUTERNAME_VALUE_NAME L"ComputerName"
  42. #define COMPUTERNAME_OPTIONAL_NAME L"OptionalNames"
  43. #define CLASS_STRING L"Network ComputerName"
  44. #define TCPIP_POLICY_ROOT \
  45. L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\System\\DNSclient"
  46. #define TCPIP_POLICY_DOMAINNAME \
  47. L"PrimaryDnsSuffix"
  48. #define TCPIP_ROOT \
  49. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
  50. #define TCPIP_HOSTNAME \
  51. L"Hostname"
  52. #define TCPIP_NV_HOSTNAME \
  53. L"NV Hostname"
  54. #define TCPIP_DOMAINNAME \
  55. L"Domain"
  56. #define TCPIP_NV_DOMAINNAME \
  57. L"NV Domain"
  58. #define DNSCACHE_ROOT \
  59. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\DnsCache\\Parameters"
  60. #define DNS_ALT_HOSTNAME \
  61. L"AlternateComputerNames"
  62. //
  63. // Allow the cluster guys to override the returned
  64. // names with their own virtual names
  65. //
  66. const PWSTR ClusterNameVars[] = {
  67. L"_CLUSTER_NETWORK_NAME_",
  68. L"_CLUSTER_NETWORK_HOSTNAME_",
  69. L"_CLUSTER_NETWORK_DOMAIN_",
  70. L"_CLUSTER_NETWORK_FQDN_"
  71. };
  72. //
  73. // Disallowed control characters (not including \0)
  74. //
  75. #define CTRL_CHARS_0 L"\001\002\003\004\005\006\007"
  76. #define CTRL_CHARS_1 L"\010\011\012\013\014\015\016\017"
  77. #define CTRL_CHARS_2 L"\020\021\022\023\024\025\026\027"
  78. #define CTRL_CHARS_3 L"\030\031\032\033\034\035\036\037"
  79. #define CTRL_CHARS_STR CTRL_CHARS_0 CTRL_CHARS_1 CTRL_CHARS_2 CTRL_CHARS_3
  80. //
  81. // Combinations of the above
  82. //
  83. #define ILLEGAL_NAME_CHARS_STR L"\"/\\[]:|<>+=;,?" CTRL_CHARS_STR
  84. WCHAR DnsApiDllString[] = L"DNSAPI.DLL";
  85. #define DNS_HOSTNAME 0
  86. #define DNS_DOMAINNAME 1
  87. DWORD
  88. BaseMultiByteToWideCharWithAlloc(
  89. LPCSTR lpBuffer,
  90. LPWSTR * ppBufferW
  91. )
  92. /*++
  93. Routine Description:
  94. Converts Ansi strings to Unicode strings and allocs it's own space.
  95. Arguments:
  96. lpBuffer - Ansi to convert
  97. ppBufferW - Unicode result
  98. Return Value:
  99. ERROR_SUCCESS, or various failures
  100. --*/
  101. {
  102. ULONG cchBuffer = 0;
  103. BOOL fSuccess = TRUE;
  104. if (lpBuffer==NULL) {
  105. *ppBufferW=NULL;
  106. return ERROR_SUCCESS;
  107. }
  108. cchBuffer = strlen(lpBuffer);
  109. // get enough space to cover the string and a trailing null
  110. *ppBufferW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchBuffer + 1) * sizeof(WCHAR));
  111. if (*ppBufferW==NULL) {
  112. return ERROR_NOT_ENOUGH_MEMORY;
  113. }
  114. fSuccess = MultiByteToWideChar(CP_ACP,
  115. 0,
  116. lpBuffer,
  117. (cchBuffer+1)*sizeof(CHAR),
  118. *ppBufferW,
  119. cchBuffer+1
  120. );
  121. if (fSuccess) {
  122. return ERROR_SUCCESS;
  123. }
  124. else {
  125. return GetLastError();
  126. }
  127. }
  128. DWORD
  129. BaseWideCharToMultiByteWithAlloc(
  130. LPCWSTR lpBuffer,
  131. LPSTR * ppBufferA
  132. )
  133. /*++
  134. Routine Description:
  135. Converts Unicode strings to Ansi strings and allocs it's own space.
  136. Arguments:
  137. lpBuffer - Unicode to convert
  138. ppBufferA - Ansi result
  139. Return Value:
  140. ERROR_SUCCESS, or various failures
  141. --*/
  142. {
  143. ULONG cchBuffer = 0;
  144. DWORD err = ERROR_SUCCESS;
  145. cchBuffer = wcslen(lpBuffer);
  146. *ppBufferA = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchBuffer + 1) * sizeof(CHAR));
  147. if (*ppBufferA==NULL) {
  148. return ERROR_NOT_ENOUGH_MEMORY;
  149. }
  150. err = WideCharToMultiByte(CP_ACP,
  151. 0,
  152. lpBuffer,
  153. cchBuffer+1,
  154. *ppBufferA,
  155. (cchBuffer+1)*sizeof(CHAR),
  156. NULL,
  157. NULL
  158. );
  159. if (err!=0) {
  160. return ERROR_SUCCESS;
  161. }
  162. else {
  163. return GetLastError();
  164. }
  165. }
  166. VOID
  167. BaseConvertCharFree(
  168. VOID * lpBuffer
  169. )
  170. /*++
  171. Routine Description:
  172. Frees space Convert functions.
  173. Arguments:
  174. lpBuffer - Buffer to free
  175. Return Value:
  176. None!
  177. --*/
  178. {
  179. if (lpBuffer!=NULL) {
  180. RtlFreeHeap(RtlProcessHeap(), 0, lpBuffer);
  181. }
  182. }
  183. BOOL
  184. BaseValidateFlags(
  185. ULONG ulFlags
  186. )
  187. /*++
  188. Routine Description:
  189. Validates unused flags. For now the flags parameter of
  190. AddLocalAlternateComputerName*
  191. RemoveLocalAlternateComputerName*
  192. EnumerateLocalAlternateComputerName*
  193. SetLocalPrimaryComputerName*
  194. are all reserved and should be 0. In subsequent releases
  195. this function should change to check for a mask of valid
  196. flags.
  197. Arguments:
  198. ulFlags -
  199. Return Value:
  200. BOOL
  201. --*/
  202. {
  203. if (ulFlags!=0) {
  204. return FALSE;
  205. }
  206. return TRUE;
  207. }
  208. BOOL
  209. BaseValidateNetbiosName(
  210. IN LPCWSTR lpComputerName
  211. )
  212. /*++
  213. Routine Description:
  214. Checks that the input is an acceptable Netbios name.
  215. Arguments:
  216. lpComputerName - name to validate
  217. Return Value:
  218. BOOL, GetLastError()
  219. --*/
  220. {
  221. NTSTATUS NtStatus = STATUS_SUCCESS;
  222. ULONG cchComputerName;
  223. ULONG AnsiComputerNameLength;
  224. cchComputerName = wcslen(lpComputerName);
  225. //
  226. // The name length limitation should be based on ANSI. (LanMan compatibility)
  227. //
  228. NtStatus = RtlUnicodeToMultiByteSize(&AnsiComputerNameLength,
  229. (LPWSTR)lpComputerName,
  230. cchComputerName * sizeof(WCHAR));
  231. if ((!NT_SUCCESS(NtStatus)) ||
  232. (AnsiComputerNameLength == 0 )||(AnsiComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
  233. SetLastError(ERROR_INVALID_PARAMETER);
  234. return(FALSE);
  235. }
  236. //
  237. // Check for illegal characters; return an error if one is found
  238. //
  239. if (wcscspn(lpComputerName, ILLEGAL_NAME_CHARS_STR) < cchComputerName) {
  240. SetLastError(ERROR_INVALID_PARAMETER);
  241. return(FALSE);
  242. }
  243. //
  244. // Check for leading or trailing spaces
  245. //
  246. if (lpComputerName[0] == L' ' ||
  247. lpComputerName[cchComputerName-1] == L' ') {
  248. SetLastError(ERROR_INVALID_PARAMETER);
  249. return(FALSE);
  250. }
  251. return(TRUE);
  252. }
  253. BOOL
  254. BaseValidateDnsNames(
  255. LPCWSTR lpDnsHostname
  256. )
  257. /*++
  258. Routine Description:
  259. Checks that the inputted name is an acceptable Dns hostname.
  260. Arguments:
  261. lpDnsHostName - name to validate
  262. Return Value:
  263. BOOL, GetLastError
  264. --*/
  265. {
  266. HANDLE DnsApi ;
  267. DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
  268. DNS_STATUS DnsStatus ;
  269. DnsApi = LoadLibraryW(DnsApiDllString);
  270. if ( !DnsApi ) {
  271. SetLastError(ERROR_DLL_NOT_FOUND);
  272. return FALSE ;
  273. }
  274. DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
  275. if ( !DnsValidateNameFn )
  276. {
  277. FreeLibrary( DnsApi );
  278. SetLastError(ERROR_INVALID_DLL);
  279. return FALSE ;
  280. }
  281. DnsStatus = DnsValidateNameFn( lpDnsHostname, DnsNameHostnameLabel );
  282. FreeLibrary( DnsApi );
  283. if ( ( DnsStatus == 0 ) ||
  284. ( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
  285. {
  286. return TRUE;
  287. }
  288. else
  289. {
  290. SetLastError(ERROR_INVALID_PARAMETER);
  291. return FALSE;
  292. }
  293. }
  294. DWORD
  295. BasepGetMultiValueAddr(
  296. IN LPWSTR lpMultiValue,
  297. IN DWORD dwIndex,
  298. OUT LPWSTR * ppFound,
  299. OUT LPDWORD pcchIndex
  300. )
  301. /*++
  302. Routine Description:
  303. Given an index into a Multivalued register (string), return
  304. the string at that index (not a copy), and it's char count location in the
  305. full multivalued string
  306. Arguments:
  307. lpMultiValue - the register string (returned from NtQueryKey)
  308. dwIndex - the index of which string to return
  309. ppFound - the string found (if found) - user shouldn't free
  310. pcchIndex - the location in lpMultiValue (in characters) of ppFound
  311. Return Value:
  312. ERROR (ERROR_NOT_FOUND if not found)
  313. --*/
  314. {
  315. DWORD i = 0;
  316. DWORD err = ERROR_SUCCESS;
  317. DWORD cchTempIndex = 0;
  318. // lpMultiValue is a concatenated string of (non-null)strings, null terminated
  319. for (i=0; (i<dwIndex) && (lpMultiValue[0] != L'\0'); i++) {
  320. cchTempIndex += wcslen(lpMultiValue) + 1;
  321. lpMultiValue += wcslen(lpMultiValue) + 1;
  322. }
  323. // if we found the correct index, it's in lpMultiValue
  324. if (lpMultiValue[0]!=L'\0') {
  325. *ppFound = lpMultiValue;
  326. *pcchIndex = cchTempIndex;
  327. err = ERROR_SUCCESS;
  328. }
  329. else {
  330. err = ERROR_NOT_FOUND;
  331. }
  332. return err;
  333. }
  334. DWORD
  335. BaseGetMultiValueIndex(
  336. IN LPWSTR lpMultiValue,
  337. IN LPCWSTR lpValue,
  338. OUT DWORD * pcchIndex
  339. )
  340. /*++
  341. Routine Description:
  342. Given a Multivalued register (string), and lpValue, return
  343. the index of lpValue in lpMultiValue (ie, the 0th string, the 1st, etc).
  344. Arguments:
  345. lpMultiValue - the register string (returned from NtQueryKey)
  346. lpValue - the string for which to search
  347. pcchIndex - the index of the string matched (if found)
  348. Return Value:
  349. ERROR (ERROR_NOT_FOUND if not found)
  350. --*/
  351. {
  352. LPWSTR lpFound = NULL;
  353. DWORD cchFoundIndex = 0;
  354. DWORD i = 0;
  355. DWORD err = ERROR_SUCCESS;
  356. BOOL fFound = FALSE;
  357. while ((err==ERROR_SUCCESS) && !fFound) {
  358. err = BasepGetMultiValueAddr(lpMultiValue,
  359. i,
  360. &lpFound,
  361. &cchFoundIndex);
  362. if (err == ERROR_SUCCESS) {
  363. if ((wcslen(lpFound)==wcslen(lpValue)) && (!_memicmp(lpFound,lpValue, wcslen(lpValue)*sizeof(WCHAR)))) {
  364. fFound = TRUE;
  365. *pcchIndex = i;
  366. }
  367. }
  368. i++;
  369. }
  370. return err;
  371. }
  372. DWORD
  373. BaseRemoveMultiValue(
  374. IN OUT LPWSTR lpMultiValue,
  375. IN DWORD dwIndex,
  376. IN OUT LPDWORD pcchMultiValue
  377. )
  378. /*++
  379. Routine Description:
  380. Given a multivalued registry value, and an index, it removes the string
  381. located at that index.
  382. Arguments:
  383. lpMultiValue - the register string (returned from NtQueryKey)
  384. dwIndex - the index of which string to remove
  385. pcchMultiValue - number of chars in lpMultiValue (before and after)
  386. Return Value:
  387. ERRORS
  388. --*/
  389. {
  390. DWORD err = ERROR_SUCCESS;
  391. LPWSTR lpRest = NULL;
  392. LPWSTR lpFound = NULL;
  393. DWORD dwIndexFound = 0;
  394. DWORD dwIndexRest = 0;
  395. err = BasepGetMultiValueAddr(lpMultiValue,
  396. dwIndex,
  397. &lpFound,
  398. &dwIndexFound);
  399. if (err==ERROR_SUCCESS) {
  400. // lpFound is a pointer to a string
  401. // inside of lpMultiValue, to delete it,
  402. // copy the rest of the string down
  403. err = BasepGetMultiValueAddr(lpMultiValue,
  404. dwIndex+1,
  405. &lpRest,
  406. &dwIndexRest);
  407. if (err == ERROR_SUCCESS) {
  408. // copy everything down
  409. memmove(lpFound,lpRest,(*pcchMultiValue - dwIndexRest)*sizeof(WCHAR));
  410. *pcchMultiValue = *pcchMultiValue - (dwIndexRest-dwIndexFound);
  411. lpMultiValue[*pcchMultiValue] = L'\0';
  412. }
  413. else if (err == ERROR_NOT_FOUND) {
  414. // string to remove is last string, simply write an extra null to orphan the string
  415. *pcchMultiValue = *pcchMultiValue - (wcslen(lpFound) +1);
  416. lpMultiValue[*pcchMultiValue] = L'\0';
  417. err = ERROR_SUCCESS;
  418. }
  419. }
  420. return err;
  421. }
  422. DWORD
  423. BaseAddMultiValue(
  424. IN OUT LPWSTR lpMultiValue,
  425. IN LPCWSTR lpValue,
  426. IN DWORD cchMultiValue
  427. )
  428. /*++
  429. Routine Description:
  430. Given a multivalued registry value, add another value.
  431. Arguments:
  432. lpMultiValue - the multivalued string (must be big enough to
  433. hold current values + lpValue plus extra NULL
  434. lpValue - the value to add
  435. cchMultiValue - the count of characters USED in lpMultivalue
  436. (not counting final null)
  437. Return Value:
  438. ERRORS
  439. --*/
  440. {
  441. memcpy(lpMultiValue + cchMultiValue, lpValue, (wcslen(lpValue)+1)*sizeof(WCHAR));
  442. lpMultiValue[cchMultiValue + wcslen(lpValue) + 1] = L'\0';
  443. return ERROR_SUCCESS;
  444. }
  445. NTSTATUS
  446. BasepGetNameFromReg(
  447. PCWSTR Path,
  448. PCWSTR Value,
  449. PWSTR Buffer,
  450. PDWORD Length
  451. )
  452. /*++
  453. Routine Description:
  454. This routine gets a string from the value at the specified registry key.
  455. Arguments:
  456. Path - Path to the registry key
  457. Value - Name of the value to retrieve
  458. Buffer - Buffer to return the value
  459. Length - size of the buffer in characters
  460. Return Value:
  461. STATUS_SUCCESS, or various failures
  462. --*/
  463. {
  464. NTSTATUS Status ;
  465. HANDLE Key ;
  466. OBJECT_ATTRIBUTES ObjA ;
  467. UNICODE_STRING KeyName;
  468. UNICODE_STRING ValueName;
  469. BYTE ValueBuffer[ REASONABLE_LENGTH ];
  470. PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
  471. BOOLEAN FreeBuffer = FALSE ;
  472. DWORD ValueLength;
  473. PWCHAR pTerminator;
  474. //
  475. // Open the node for the Subkey
  476. //
  477. RtlInitUnicodeString(&KeyName, Path );
  478. InitializeObjectAttributes(&ObjA,
  479. &KeyName,
  480. OBJ_CASE_INSENSITIVE,
  481. NULL,
  482. NULL
  483. );
  484. Status = NtOpenKey(&Key, KEY_READ, &ObjA );
  485. if (NT_SUCCESS(Status)) {
  486. RtlInitUnicodeString( &ValueName, Value );
  487. Status = NtQueryValueKey(Key,
  488. &ValueName,
  489. KeyValueFullInformation,
  490. pKeyValueInformation,
  491. REASONABLE_LENGTH ,
  492. &ValueLength);
  493. if ( Status == STATUS_BUFFER_OVERFLOW )
  494. {
  495. pKeyValueInformation = RtlAllocateHeap( RtlProcessHeap(),
  496. 0,
  497. ValueLength );
  498. if ( pKeyValueInformation )
  499. {
  500. FreeBuffer = TRUE ;
  501. Status = NtQueryValueKey( Key,
  502. &ValueName,
  503. KeyValueFullInformation,
  504. pKeyValueInformation,
  505. ValueLength,
  506. &ValueLength );
  507. }
  508. }
  509. if ( NT_SUCCESS(Status) ) {
  510. //
  511. // If the user's buffer is big enough, move it in
  512. // First see if it's null terminated. If it is, pretend like
  513. // it's not.
  514. //
  515. pTerminator = (PWCHAR)((PBYTE) pKeyValueInformation +
  516. pKeyValueInformation->DataOffset +
  517. pKeyValueInformation->DataLength);
  518. pTerminator--;
  519. if (*pTerminator == L'\0') {
  520. pKeyValueInformation->DataLength -= sizeof(WCHAR);
  521. }
  522. if ( ( *Length >= pKeyValueInformation->DataLength/sizeof(WCHAR) + 1) &&
  523. ( Buffer != NULL ) ) {
  524. //
  525. // This isn't guaranteed to be NULL terminated, make it so
  526. //
  527. RtlCopyMemory(Buffer,
  528. (LPWSTR)((PBYTE) pKeyValueInformation +
  529. pKeyValueInformation->DataOffset),
  530. pKeyValueInformation->DataLength);
  531. pTerminator = (PWCHAR) ((PBYTE) Buffer +
  532. pKeyValueInformation->DataLength);
  533. *pTerminator = L'\0';
  534. //
  535. // Return the number of characters to the caller
  536. //
  537. *Length = pKeyValueInformation->DataLength / sizeof(WCHAR) ;
  538. }
  539. else {
  540. Status = STATUS_BUFFER_OVERFLOW;
  541. *Length = pKeyValueInformation->DataLength/sizeof(WCHAR) + 1;
  542. }
  543. }
  544. NtClose( Key );
  545. }
  546. if ( FreeBuffer )
  547. {
  548. RtlFreeHeap( RtlProcessHeap(), 0, pKeyValueInformation );
  549. }
  550. return Status ;
  551. }
  552. NTSTATUS
  553. BaseSetNameInReg(
  554. PCWSTR Path,
  555. PCWSTR Value,
  556. PCWSTR Buffer
  557. )
  558. /*++
  559. Routine Description:
  560. This routine sets a string in the value at the registry key.
  561. Arguments:
  562. Path - Path to the registry key
  563. Value - Name of the value to set
  564. Buffer - Buffer to set
  565. Return Value:
  566. STATUS_SUCCESS, or various failures
  567. --*/
  568. {
  569. NTSTATUS NtStatus;
  570. UNICODE_STRING KeyName;
  571. UNICODE_STRING ValueName;
  572. OBJECT_ATTRIBUTES ObjectAttributes;
  573. HANDLE hKey = NULL;
  574. ULONG ValueLength;
  575. //
  576. // Open the ComputerName\ComputerName node
  577. //
  578. RtlInitUnicodeString(&KeyName, Path);
  579. InitializeObjectAttributes(&ObjectAttributes,
  580. &KeyName,
  581. OBJ_CASE_INSENSITIVE,
  582. NULL,
  583. NULL
  584. );
  585. NtStatus = NtOpenKey(&hKey, KEY_READ | KEY_WRITE, &ObjectAttributes);
  586. if ( !NT_SUCCESS( NtStatus ) )
  587. {
  588. return NtStatus ;
  589. }
  590. //
  591. // Update the value under this key
  592. //
  593. RtlInitUnicodeString(&ValueName, Value);
  594. ValueLength = (wcslen( Buffer ) + 1) * sizeof(WCHAR);
  595. NtStatus = NtSetValueKey(hKey,
  596. &ValueName,
  597. 0,
  598. REG_SZ,
  599. (LPWSTR) Buffer,
  600. ValueLength);
  601. if ( NT_SUCCESS( NtStatus ) )
  602. {
  603. NtFlushKey( hKey );
  604. }
  605. NtClose(hKey);
  606. return NtStatus ;
  607. }
  608. NTSTATUS
  609. BaseSetMultiNameInReg(
  610. PCWSTR Path,
  611. PCWSTR Value,
  612. PCWSTR Buffer,
  613. DWORD BufferSize
  614. )
  615. /*++
  616. Routine Description:
  617. This routine sets a string in the value at the specified multivalued registry key.
  618. Arguments:
  619. Path - Path to the registry key
  620. Value - Name of the value to set
  621. Buffer - Buffer to set
  622. BufferSize - Size of the buffer in characters
  623. This is needed since there can be
  624. many nulls in the buffer which we
  625. want to write
  626. Return Value:
  627. STATUS_SUCCESS, or various failures
  628. --*/
  629. {
  630. NTSTATUS NtStatus = STATUS_SUCCESS;
  631. UNICODE_STRING KeyName;
  632. UNICODE_STRING ValueName;
  633. OBJECT_ATTRIBUTES ObjectAttributes;
  634. HANDLE hKey = NULL;
  635. //
  636. // Open the ComputerName\ComputerName node
  637. //
  638. RtlInitUnicodeString(&KeyName, Path);
  639. InitializeObjectAttributes(&ObjectAttributes,
  640. &KeyName,
  641. OBJ_CASE_INSENSITIVE,
  642. NULL,
  643. NULL
  644. );
  645. NtStatus = NtCreateKey(&hKey,
  646. KEY_READ | KEY_WRITE,
  647. &ObjectAttributes,
  648. 0,
  649. NULL,
  650. 0,
  651. NULL);
  652. if ( !NT_SUCCESS( NtStatus ) )
  653. {
  654. return NtStatus ;
  655. }
  656. //
  657. // Update the value under this key
  658. //
  659. RtlInitUnicodeString(&ValueName, Value);
  660. NtStatus = NtSetValueKey(hKey,
  661. &ValueName,
  662. 0,
  663. REG_MULTI_SZ,
  664. (LPWSTR) Buffer,
  665. BufferSize);
  666. if ( NT_SUCCESS( NtStatus ) )
  667. {
  668. NtFlushKey( hKey );
  669. }
  670. NtClose(hKey);
  671. return NtStatus ;
  672. }
  673. NTSTATUS
  674. BaseCreateMultiValue(
  675. PCWSTR Path,
  676. PCWSTR Value,
  677. PCWSTR Buffer
  678. )
  679. /*++
  680. Routine Description:
  681. Create a multivalued registry value and initialize it with Buffer.
  682. Arguments:
  683. Path - Path to the registry key
  684. Value - Name of the value to set
  685. Buffer - Buffer to set
  686. Return Value:
  687. STATUS_SUCCESS, or various failures
  688. --*/
  689. {
  690. NTSTATUS NtStatus = STATUS_SUCCESS;
  691. LPWSTR lpMultiValue = NULL;
  692. lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG ( TMP_TAG ), (wcslen(Buffer)+2)*sizeof(WCHAR));
  693. if (lpMultiValue==NULL) {
  694. NtStatus = STATUS_NO_MEMORY;
  695. }
  696. else {
  697. memcpy(lpMultiValue, Buffer, wcslen(Buffer)*sizeof(WCHAR));
  698. lpMultiValue[wcslen(Buffer)] = L'\0';
  699. lpMultiValue[wcslen(Buffer)+1] = L'\0';
  700. NtStatus = BaseSetMultiNameInReg(Path,
  701. Value,
  702. lpMultiValue,
  703. (wcslen(Buffer)+2)*sizeof(WCHAR));
  704. RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
  705. }
  706. return NtStatus;
  707. }
  708. NTSTATUS
  709. BaseAddMultiNameInReg(
  710. PCWSTR Path,
  711. PCWSTR Value,
  712. PCWSTR Buffer
  713. )
  714. /*++
  715. Routine Description:
  716. This routine adds a string to the values at the specified multivalued registry key.
  717. If the value already exists in the key, it does nothing.
  718. Arguments:
  719. Path - Path to the registry key
  720. Value - Name of the value
  721. Buffer - Buffer to add
  722. Return Value:
  723. STATUS_SUCCESS, or various failures
  724. --*/
  725. {
  726. NTSTATUS NtStatus = STATUS_SUCCESS;
  727. LPWSTR lpMultiValue = NULL;
  728. ULONG cchMultiValue = 0;
  729. DWORD dwIndex = 0;
  730. DWORD err = ERROR_SUCCESS;
  731. NtStatus = BasepGetNameFromReg(Path,
  732. Value,
  733. lpMultiValue,
  734. &cchMultiValue);
  735. if ( NtStatus==STATUS_NOT_FOUND || NtStatus==STATUS_OBJECT_NAME_NOT_FOUND) {
  736. // create it, then we are done
  737. NtStatus = BaseCreateMultiValue(Path,Value,Buffer);
  738. return NtStatus;
  739. } else if ( NtStatus==STATUS_BUFFER_OVERFLOW ) {
  740. lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchMultiValue+2+wcslen(Buffer))*sizeof(WCHAR));
  741. if (lpMultiValue==NULL) {
  742. NtStatus = STATUS_NO_MEMORY;
  743. }
  744. else {
  745. NtStatus = BasepGetNameFromReg(Path,
  746. Value,
  747. lpMultiValue,
  748. &cchMultiValue);
  749. }
  750. }
  751. if (NT_SUCCESS( NtStatus)) {
  752. // does it already exist in this structure?
  753. err = BaseGetMultiValueIndex(lpMultiValue,
  754. Buffer, &dwIndex);
  755. // if err==ERROR_SUCCESS, then the above function found the string already in the value.
  756. // don't add a duplicate
  757. if (err!=ERROR_SUCCESS) {
  758. err = BaseAddMultiValue(lpMultiValue, Buffer, cchMultiValue);
  759. if (err == ERROR_SUCCESS) {
  760. NtStatus = BaseSetMultiNameInReg(Path, Value, lpMultiValue, (cchMultiValue+2+wcslen(Buffer))*sizeof(WCHAR));
  761. }
  762. }
  763. }
  764. if (lpMultiValue) {
  765. RtlFreeHeap( RtlProcessHeap(), 0, lpMultiValue);
  766. }
  767. return NtStatus ;
  768. }
  769. NTSTATUS
  770. BaseRemoveMultiNameFromReg(
  771. PCWSTR Path,
  772. PCWSTR Value,
  773. PCWSTR Buffer
  774. )
  775. /*++
  776. Routine Description:
  777. Removes a name from a multivalued registry. If the value exists more than once in the
  778. list, removes them all.
  779. Arguments:
  780. Path - Path to the registry key
  781. Value - Name of the value
  782. Buffer - Buffer to remove
  783. Return Value:
  784. ERRORS
  785. --*/
  786. {
  787. NTSTATUS NtStatus = STATUS_SUCCESS;
  788. DWORD err = ERROR_SUCCESS;
  789. DWORD dwIndex = 0;
  790. LPWSTR lpMultiValue = NULL;
  791. ULONG cchNames = 0;
  792. BOOL fNameRemoved = FALSE;
  793. NtStatus = BasepGetNameFromReg(Path,
  794. Value,
  795. lpMultiValue,
  796. &cchNames);
  797. if (NtStatus==STATUS_BUFFER_OVERFLOW) {
  798. lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchNames) * sizeof(WCHAR));
  799. if (lpMultiValue==NULL) {
  800. NtStatus = STATUS_NO_MEMORY;
  801. }
  802. else {
  803. NtStatus = BasepGetNameFromReg(Path,
  804. Value,
  805. lpMultiValue,
  806. &cchNames);
  807. err = RtlNtStatusToDosError(NtStatus);
  808. if (err == ERROR_SUCCESS) {
  809. // search for and remove all values in structure
  810. while (err==ERROR_SUCCESS) {
  811. err = BaseGetMultiValueIndex(lpMultiValue,
  812. Buffer,
  813. &dwIndex);
  814. if (err == ERROR_SUCCESS) {
  815. err = BaseRemoveMultiValue(lpMultiValue,
  816. dwIndex,
  817. &cchNames);
  818. fNameRemoved = TRUE;
  819. }
  820. }
  821. // if we removed a name, write it to the registry...
  822. if (fNameRemoved) {
  823. NtStatus = BaseSetMultiNameInReg(
  824. Path,
  825. Value,
  826. lpMultiValue,
  827. (cchNames+1)*sizeof(WCHAR));
  828. }
  829. else {
  830. // Nothing to remove! ERRROR
  831. NtStatus = STATUS_NOT_FOUND;
  832. }
  833. }
  834. RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
  835. }
  836. }
  837. return NtStatus;
  838. }
  839. BOOL
  840. BaseSetNetbiosName(
  841. IN LPCWSTR lpComputerName
  842. )
  843. /*++
  844. Routine Description:
  845. Sets the computer's net bios name
  846. Arguments:
  847. lpComputerName - name to set
  848. Return Value:
  849. BOOL, GetLastError()
  850. --*/
  851. {
  852. NTSTATUS NtStatus ;
  853. //
  854. // Validate that the supplied computername is valid (not too long,
  855. // no incorrect characters, no leading or trailing spaces)
  856. //
  857. if (!BaseValidateNetbiosName(lpComputerName)) {
  858. return(FALSE);
  859. }
  860. //
  861. // Open the ComputerName\ComputerName node
  862. //
  863. NtStatus = BaseSetNameInReg( NON_VOLATILE_COMPUTERNAME_NODE,
  864. COMPUTERNAME_VALUE_NAME,
  865. lpComputerName );
  866. if ( !NT_SUCCESS( NtStatus ))
  867. {
  868. BaseSetLastNTError( NtStatus );
  869. return FALSE ;
  870. }
  871. return TRUE ;
  872. }
  873. BOOL
  874. BaseSetDnsName(
  875. LPCWSTR lpComputerName
  876. )
  877. /*++
  878. Routine Description:
  879. Sets the computer's Dns hostname
  880. Arguments:
  881. lpComputerName - name to set
  882. Return Value:
  883. BOOL, GetLastError()
  884. --*/
  885. {
  886. UNICODE_STRING NewComputerName ;
  887. UNICODE_STRING DnsName ;
  888. NTSTATUS Status ;
  889. BOOL Return ;
  890. HANDLE DnsApi ;
  891. DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
  892. DNS_STATUS DnsStatus ;
  893. DnsApi = LoadLibraryW(DnsApiDllString);
  894. if ( !DnsApi )
  895. {
  896. return FALSE ;
  897. }
  898. DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
  899. if ( !DnsValidateNameFn )
  900. {
  901. FreeLibrary( DnsApi );
  902. return FALSE ;
  903. }
  904. DnsStatus = DnsValidateNameFn( lpComputerName, DnsNameHostnameLabel );
  905. FreeLibrary( DnsApi );
  906. if ( ( DnsStatus == 0 ) ||
  907. ( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
  908. {
  909. Status = BaseSetNameInReg( TCPIP_ROOT,
  910. TCPIP_NV_HOSTNAME,
  911. lpComputerName );
  912. }
  913. else
  914. {
  915. Status = STATUS_INVALID_PARAMETER ;
  916. }
  917. if ( NT_SUCCESS( Status ) )
  918. {
  919. RtlInitUnicodeString( &DnsName, lpComputerName );
  920. Status = RtlDnsHostNameToComputerName( &NewComputerName,
  921. &DnsName,
  922. TRUE );
  923. if ( NT_SUCCESS( Status ) )
  924. {
  925. Return = BaseSetNetbiosName( NewComputerName.Buffer );
  926. RtlFreeUnicodeString( &NewComputerName );
  927. if ( !Return )
  928. {
  929. //
  930. // What? Rollback?
  931. //
  932. return FALSE ;
  933. }
  934. return TRUE ;
  935. }
  936. }
  937. BaseSetLastNTError( Status ) ;
  938. return FALSE ;
  939. }
  940. BOOL
  941. BaseSetDnsDomain(
  942. LPCWSTR lpName
  943. )
  944. /*++
  945. Routine Description:
  946. Sets the computer's Dns domain name
  947. Arguments:
  948. lpName - name to set
  949. Return Value:
  950. BOOL, GetLastError()
  951. --*/
  952. {
  953. NTSTATUS Status ;
  954. HANDLE DnsApi ;
  955. DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
  956. DNS_STATUS DnsStatus ;
  957. //
  958. // Special case the empty string, which is legal, but not according to dnsapi
  959. //
  960. if ( *lpName )
  961. {
  962. DnsApi = LoadLibraryW(DnsApiDllString);
  963. if ( !DnsApi )
  964. {
  965. return FALSE ;
  966. }
  967. DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
  968. if ( !DnsValidateNameFn )
  969. {
  970. FreeLibrary( DnsApi );
  971. return FALSE ;
  972. }
  973. DnsStatus = DnsValidateNameFn( lpName, DnsNameDomain );
  974. FreeLibrary( DnsApi );
  975. }
  976. else
  977. {
  978. DnsStatus = 0 ;
  979. }
  980. //
  981. // If the name is good, then keep it.
  982. //
  983. if ( ( DnsStatus == 0 ) ||
  984. ( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
  985. {
  986. Status = BaseSetNameInReg(
  987. TCPIP_ROOT,
  988. TCPIP_NV_DOMAINNAME,
  989. lpName );
  990. }
  991. else
  992. {
  993. Status = STATUS_INVALID_PARAMETER ;
  994. }
  995. if ( !NT_SUCCESS( Status ) )
  996. {
  997. BaseSetLastNTError( Status );
  998. return FALSE ;
  999. }
  1000. return TRUE ;
  1001. }
  1002. BOOL
  1003. BaseSetAltNetBiosName(
  1004. IN LPCWSTR lpComputerName
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. Sets the computer's alternate net bios name
  1009. Arguments:
  1010. lpComputerName - name to set
  1011. Return Value:
  1012. BOOL, GetLastError()
  1013. --*/
  1014. {
  1015. NTSTATUS NtStatus = STATUS_SUCCESS;
  1016. if (!BaseValidateNetbiosName(lpComputerName)) {
  1017. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  1018. return(FALSE);
  1019. }
  1020. NtStatus = BaseAddMultiNameInReg(
  1021. ALT_COMPUTERNAME_NODE,
  1022. COMPUTERNAME_OPTIONAL_NAME,
  1023. lpComputerName );
  1024. if ( !NT_SUCCESS( NtStatus ))
  1025. {
  1026. BaseSetLastNTError( NtStatus );
  1027. return FALSE ;
  1028. }
  1029. return TRUE ;
  1030. }
  1031. BOOL
  1032. BaseSetAltDnsFQHostname(
  1033. IN LPCWSTR lpDnsFQHostname
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Sets the computer's alternate fully qualified Dns name
  1038. Arguments:
  1039. lpDnsFQHostname - name to set
  1040. Return Value:
  1041. BOOL, GetLastError()
  1042. --*/
  1043. {
  1044. NTSTATUS NtStatus = STATUS_SUCCESS;
  1045. NtStatus = BaseAddMultiNameInReg(
  1046. DNSCACHE_ROOT,
  1047. DNS_ALT_HOSTNAME,
  1048. lpDnsFQHostname);
  1049. if ( !NT_SUCCESS( NtStatus ))
  1050. {
  1051. BaseSetLastNTError( NtStatus );
  1052. return FALSE ;
  1053. }
  1054. return TRUE ;
  1055. }
  1056. BOOL
  1057. BaseIsAltDnsFQHostname(
  1058. LPCWSTR lpAltDnsFQHostname
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. Verifies if lpAltDnsFQHostname is a previosly defined
  1063. alternate dns name
  1064. Arguments:
  1065. lpDnsFQHostname - name to check
  1066. Return Value:
  1067. TRUE if verifiably in use, FALSE otherwise, GetLastError()
  1068. --*/
  1069. {
  1070. NTSTATUS NtStatus = STATUS_SUCCESS;
  1071. LPWSTR lpNames = NULL;
  1072. ULONG cchNames = 0;
  1073. BOOL fFound = FALSE;
  1074. DWORD dwIndex = 0;
  1075. DWORD err = ERROR_SUCCESS;
  1076. NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
  1077. DNS_ALT_HOSTNAME,
  1078. lpNames,
  1079. &cchNames);
  1080. if (NtStatus==STATUS_BUFFER_OVERFLOW) {
  1081. lpNames = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchNames) * sizeof(WCHAR));
  1082. if (lpNames!=NULL) {
  1083. NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
  1084. DNS_ALT_HOSTNAME,
  1085. lpNames,
  1086. &cchNames);
  1087. err = RtlNtStatusToDosError(NtStatus);
  1088. if (err == ERROR_SUCCESS) {
  1089. err = BaseGetMultiValueIndex(lpNames,
  1090. lpAltDnsFQHostname,
  1091. &dwIndex);
  1092. fFound = err==ERROR_SUCCESS;
  1093. }
  1094. RtlFreeHeap( RtlProcessHeap(), 0, lpNames);
  1095. }
  1096. }
  1097. return fFound;
  1098. }
  1099. BOOL
  1100. BaseRemoveAltNetBiosName(
  1101. IN LPCWSTR lpAltComputerName
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Removes an alternate net bios name
  1106. Arguments:
  1107. lpAltComputerName - name to remove
  1108. Return Value:
  1109. BOOL, GetLastError()
  1110. --*/
  1111. {
  1112. NTSTATUS NtStatus = STATUS_SUCCESS;
  1113. NtStatus = BaseRemoveMultiNameFromReg ( ALT_COMPUTERNAME_NODE,
  1114. COMPUTERNAME_OPTIONAL_NAME,
  1115. lpAltComputerName );
  1116. if ( !NT_SUCCESS( NtStatus ))
  1117. {
  1118. BaseSetLastNTError( NtStatus );
  1119. return FALSE ;
  1120. }
  1121. return TRUE ;
  1122. }
  1123. BOOL
  1124. BaseRemoveAltDnsFQHostname(
  1125. IN LPCWSTR lpAltDnsFQHostname
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Removes an alternate Dns hostname
  1130. Arguments:
  1131. lpAltDnsFqHostname - name to remove
  1132. Return Value:
  1133. BOOL, GetLastError()
  1134. --*/
  1135. {
  1136. NTSTATUS NtStatus = STATUS_SUCCESS;
  1137. NtStatus = BaseRemoveMultiNameFromReg ( DNSCACHE_ROOT,
  1138. DNS_ALT_HOSTNAME,
  1139. lpAltDnsFQHostname );
  1140. if ( !NT_SUCCESS( NtStatus ))
  1141. {
  1142. BaseSetLastNTError( NtStatus );
  1143. return FALSE ;
  1144. }
  1145. return TRUE ;
  1146. }
  1147. DWORD
  1148. BaseEnumAltDnsFQHostnames(
  1149. OUT LPWSTR lpAltDnsFQHostnames,
  1150. IN OUT LPDWORD nSize
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Wrapper for BasepGetNameFromReg to return ERRORS, instead of STATUS
  1155. --*/
  1156. {
  1157. NTSTATUS status = STATUS_SUCCESS;
  1158. status = BasepGetNameFromReg(
  1159. DNSCACHE_ROOT,
  1160. DNS_ALT_HOSTNAME,
  1161. lpAltDnsFQHostnames,
  1162. nSize);
  1163. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1164. if ((lpAltDnsFQHostnames!=NULL) && (*nSize>0)) {
  1165. lpAltDnsFQHostnames[0]=L'\0';
  1166. *nSize=0;
  1167. status=STATUS_SUCCESS;
  1168. }
  1169. else {
  1170. *nSize=1;
  1171. status=STATUS_BUFFER_OVERFLOW;
  1172. }
  1173. }
  1174. return RtlNtStatusToDosError(status);
  1175. }
  1176. LPWSTR
  1177. BaseParseDnsName(
  1178. IN LPCWSTR lpDnsName,
  1179. IN ULONG NamePart
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Given a dns name, parse out either the hostname or the domain name.
  1184. Arguments:
  1185. lpDnsName - a dns name, of the form hostname.domain - domain name optional
  1186. NamePart - DNS_HOSTNAME or DNS_DOMAINNAME
  1187. Return Value:
  1188. String requested
  1189. --*/
  1190. {
  1191. DWORD cchCharIndex = 0;
  1192. ULONG cchName = 0;
  1193. LPWSTR lpName = NULL;
  1194. if (lpDnsName==NULL) {
  1195. return NULL;
  1196. }
  1197. cchCharIndex = wcscspn(lpDnsName, L".");
  1198. if (NamePart==DNS_HOSTNAME) {
  1199. cchName = cchCharIndex;
  1200. }
  1201. else {
  1202. if (cchCharIndex==wcslen(lpDnsName)) {
  1203. // no period found,
  1204. cchName = 0;
  1205. }
  1206. else {
  1207. cchName = wcslen(lpDnsName)-(cchCharIndex+1);
  1208. }
  1209. }
  1210. lpName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchName + 1)*sizeof(WCHAR));
  1211. if (lpName==NULL) {
  1212. return NULL;
  1213. }
  1214. // copy the correct part into the structure
  1215. if (NamePart==DNS_HOSTNAME) {
  1216. wcsncpy(lpName, lpDnsName, cchName);
  1217. }
  1218. else {
  1219. wcsncpy(lpName, (LPWSTR)(lpDnsName + cchCharIndex + 1), cchName);
  1220. }
  1221. lpName[cchName] = L'\0';
  1222. return lpName;
  1223. }
  1224. BOOL
  1225. BaseIsNetBiosNameInUse(
  1226. LPWSTR lpCompName
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. Verify whether lpCompName is being used by any alternate DNS names
  1231. (ie whether any existing alternate DNS names map to lpCompName with
  1232. DnsHostnameToComputerNameW)
  1233. Arguments:
  1234. lpCompName - net bios name to verify
  1235. Return Value:
  1236. FALSE if verifiably is not being used, true otherwise, GetLastError()
  1237. --*/
  1238. {
  1239. NTSTATUS NtStatus = STATUS_SUCCESS;
  1240. LPWSTR lpMultiValue = NULL;
  1241. ULONG cchMultiValue = 0;
  1242. LPWSTR lpAltDnsFQHostname = NULL;
  1243. ULONG cchAltDnsHostname = 0;
  1244. DWORD dwIndex = 0;
  1245. LPWSTR lpAltCompName = NULL;
  1246. ULONG cchAltCompName = 0;
  1247. DWORD err = ERROR_SUCCESS;
  1248. BOOL fInUse = FALSE;
  1249. BOOL fIsNetBiosNameInUse = TRUE;
  1250. NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
  1251. DNS_ALT_HOSTNAME,
  1252. lpMultiValue,
  1253. &cchMultiValue);
  1254. err = RtlNtStatusToDosError(NtStatus);
  1255. if (err==ERROR_MORE_DATA) {
  1256. lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchMultiValue * sizeof(WCHAR));
  1257. if (lpMultiValue==NULL) {
  1258. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1259. return TRUE;
  1260. }
  1261. NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
  1262. DNS_ALT_HOSTNAME,
  1263. lpMultiValue,
  1264. &cchMultiValue);
  1265. err=RtlNtStatusToDosError(NtStatus);
  1266. }
  1267. if (err == ERROR_SUCCESS) {
  1268. dwIndex = 0;
  1269. while (err == ERROR_SUCCESS) {
  1270. err = BasepGetMultiValueAddr(lpMultiValue,
  1271. dwIndex,
  1272. &lpAltDnsFQHostname,
  1273. &cchAltDnsHostname);
  1274. // get net bios names
  1275. if (err == ERROR_SUCCESS) {
  1276. if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname,
  1277. lpAltCompName,
  1278. &cchAltCompName)) {
  1279. err = GetLastError();
  1280. if (err==ERROR_MORE_DATA) {
  1281. // DnsHostNameToComputerNameW bug
  1282. cchAltCompName += 1;
  1283. // DnsHostNameToComputerNameW bug
  1284. lpAltCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchAltCompName*sizeof(WCHAR));
  1285. if (lpAltCompName==NULL) {
  1286. err = ERROR_NOT_ENOUGH_MEMORY;
  1287. }
  1288. else {
  1289. if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname, lpAltCompName, &cchAltCompName)) {
  1290. err = GetLastError();
  1291. } else {
  1292. err = ERROR_SUCCESS;
  1293. }
  1294. }
  1295. }
  1296. }
  1297. if (err==ERROR_SUCCESS) {
  1298. if (!_wcsicmp(lpAltCompName, lpCompName)) {
  1299. fInUse = TRUE;
  1300. }
  1301. }
  1302. }
  1303. dwIndex++;
  1304. }
  1305. // exits the above while loop when err==ERROR_NOT_FOUND, whether found or not
  1306. if (err==ERROR_NOT_FOUND) {
  1307. fIsNetBiosNameInUse = fInUse;
  1308. err = ERROR_SUCCESS;
  1309. }
  1310. else {
  1311. // error, default to in use
  1312. fIsNetBiosNameInUse = TRUE;
  1313. }
  1314. }
  1315. if (lpMultiValue) {
  1316. RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
  1317. }
  1318. if (lpAltCompName) {
  1319. RtlFreeHeap(RtlProcessHeap(), 0, lpAltCompName);
  1320. }
  1321. return fIsNetBiosNameInUse;
  1322. }
  1323. //
  1324. // Worker routine
  1325. //
  1326. NTSTATUS
  1327. GetNameFromValue(
  1328. HANDLE hKey,
  1329. LPWSTR SubKeyName,
  1330. LPWSTR ValueValue,
  1331. LPDWORD nSize
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This returns the value of "ComputerName" value entry under the subkey
  1336. SubKeyName relative to hKey. This is used to get the value of the
  1337. ActiveComputerName or ComputerName values.
  1338. Arguments:
  1339. hKey - handle to the Key the SubKey exists under
  1340. SubKeyName - name of the subkey to look for the value under
  1341. ValueValue - where the value of the value entry will be returned
  1342. nSize - pointer to the size (in characters) of the ValueValue buffer
  1343. Return Value:
  1344. --*/
  1345. {
  1346. #define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + \
  1347. (sizeof( COMPUTERNAME_VALUE_NAME ) + MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR))
  1348. NTSTATUS NtStatus;
  1349. UNICODE_STRING KeyName;
  1350. UNICODE_STRING ValueName;
  1351. OBJECT_ATTRIBUTES ObjectAttributes;
  1352. HANDLE hSubKey;
  1353. BYTE ValueBuffer[VALUE_BUFFER_SIZE];
  1354. PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
  1355. DWORD ValueLength;
  1356. PWCHAR pTerminator;
  1357. //
  1358. // Open the node for the Subkey
  1359. //
  1360. RtlInitUnicodeString(&KeyName, SubKeyName);
  1361. InitializeObjectAttributes(&ObjectAttributes,
  1362. &KeyName,
  1363. OBJ_CASE_INSENSITIVE,
  1364. hKey,
  1365. NULL
  1366. );
  1367. NtStatus = NtOpenKey(&hSubKey, KEY_READ, &ObjectAttributes);
  1368. if (NT_SUCCESS(NtStatus)) {
  1369. RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
  1370. NtStatus = NtQueryValueKey(hSubKey,
  1371. &ValueName,
  1372. KeyValueFullInformation,
  1373. pKeyValueInformation,
  1374. VALUE_BUFFER_SIZE,
  1375. &ValueLength);
  1376. NtClose(hSubKey);
  1377. if (NT_SUCCESS(NtStatus) &&
  1378. (pKeyValueInformation->DataLength > 0 )) {
  1379. //
  1380. // If the user's buffer is big enough, move it in
  1381. // First see if it's null terminated. If it is, pretend like
  1382. // it's not.
  1383. //
  1384. pTerminator = (PWCHAR)((PBYTE) pKeyValueInformation +
  1385. pKeyValueInformation->DataOffset +
  1386. pKeyValueInformation->DataLength);
  1387. pTerminator--;
  1388. if (*pTerminator == L'\0') {
  1389. pKeyValueInformation->DataLength -= sizeof(WCHAR);
  1390. }
  1391. if (*nSize >= pKeyValueInformation->DataLength/sizeof(WCHAR) + 1) {
  1392. //
  1393. // This isn't guaranteed to be NULL terminated, make it so
  1394. //
  1395. RtlCopyMemory(ValueValue,
  1396. (LPWSTR)((PBYTE) pKeyValueInformation +
  1397. pKeyValueInformation->DataOffset),
  1398. pKeyValueInformation->DataLength);
  1399. pTerminator = (PWCHAR) ((PBYTE) ValueValue +
  1400. pKeyValueInformation->DataLength);
  1401. *pTerminator = L'\0';
  1402. //
  1403. // Return the number of characters to the caller
  1404. //
  1405. *nSize = wcslen(ValueValue);
  1406. }
  1407. else {
  1408. NtStatus = STATUS_BUFFER_OVERFLOW;
  1409. *nSize = pKeyValueInformation->DataLength/sizeof(WCHAR) + 1;
  1410. }
  1411. }
  1412. else {
  1413. //
  1414. // If the value has been deleted (zero length data),
  1415. // return object not found.
  1416. //
  1417. if ( NT_SUCCESS( NtStatus ) )
  1418. {
  1419. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND ;
  1420. }
  1421. }
  1422. }
  1423. return(NtStatus);
  1424. }
  1425. //
  1426. // UNICODE APIs
  1427. //
  1428. BOOL
  1429. WINAPI
  1430. GetComputerNameW (
  1431. LPWSTR lpBuffer,
  1432. LPDWORD nSize
  1433. )
  1434. /*++
  1435. Routine Description:
  1436. This returns the active computername. This is the computername when the
  1437. system was last booted. If this is changed (via SetComputerName) it does
  1438. not take effect until the next system boot.
  1439. Arguments:
  1440. lpBuffer - Points to the buffer that is to receive the
  1441. null-terminated character string containing the computer name.
  1442. nSize - Specifies the maximum size (in characters) of the buffer. This
  1443. value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
  1444. sufficient room in the buffer for the computer name. The length
  1445. of the string is returned in nSize.
  1446. Return Value:
  1447. TRUE on success, FALSE on failure.
  1448. --*/
  1449. {
  1450. NTSTATUS NtStatus;
  1451. UNICODE_STRING KeyName;
  1452. UNICODE_STRING Class;
  1453. UNICODE_STRING ValueName;
  1454. OBJECT_ATTRIBUTES ObjectAttributes;
  1455. HANDLE hKey = NULL;
  1456. HANDLE hNewKey = NULL;
  1457. ULONG Disposition;
  1458. ULONG ValueLength;
  1459. BOOL ReturnValue;
  1460. DWORD Status;
  1461. DWORD errcode;
  1462. //
  1463. // First check to see if the cluster computername variable is set.
  1464. // If so, this overrides the actual computername to fool the application
  1465. // into working when its network name and computer name are different.
  1466. //
  1467. ValueLength = GetEnvironmentVariableW(L"_CLUSTER_NETWORK_NAME_",
  1468. lpBuffer,
  1469. *nSize);
  1470. if (ValueLength != 0) {
  1471. //
  1472. // The environment variable exists, return it directly but make sure
  1473. // we honor return semantics
  1474. //
  1475. ReturnValue = ( *nSize >= ValueLength ? TRUE : FALSE );
  1476. if ( !ReturnValue ) {
  1477. SetLastError( ERROR_BUFFER_OVERFLOW );
  1478. }
  1479. *nSize = ValueLength;
  1480. return(ReturnValue);
  1481. }
  1482. if ( (gpTermsrvGetComputerName) &&
  1483. ((errcode = gpTermsrvGetComputerName(lpBuffer, nSize)) != ERROR_RETRY) ) {
  1484. if (errcode == ERROR_BUFFER_OVERFLOW ) {
  1485. ReturnValue = FALSE;
  1486. goto Cleanup;
  1487. } else {
  1488. goto GoodReturn;
  1489. }
  1490. }
  1491. //
  1492. // Open the Computer node, both computername keys are relative
  1493. // to this node.
  1494. //
  1495. RtlInitUnicodeString(&KeyName, COMPUTERNAME_ROOT);
  1496. InitializeObjectAttributes(&ObjectAttributes,
  1497. &KeyName,
  1498. OBJ_CASE_INSENSITIVE,
  1499. NULL,
  1500. NULL
  1501. );
  1502. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  1503. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1504. //
  1505. // This should never happen! This key should have been created
  1506. // at setup, and protected by an ACL so that only the ADMIN could
  1507. // write to it. Generate an event, and return a NULL computername.
  1508. //
  1509. // NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
  1510. //
  1511. // Return a NULL computername
  1512. //
  1513. if (ARGUMENT_PRESENT(lpBuffer))
  1514. {
  1515. lpBuffer[0] = L'\0';
  1516. }
  1517. *nSize = 0;
  1518. goto GoodReturn;
  1519. }
  1520. if (!NT_SUCCESS(NtStatus)) {
  1521. //
  1522. // Some other error, return it to the caller
  1523. //
  1524. goto ErrorReturn;
  1525. }
  1526. //
  1527. // Try to get the name from the volatile key
  1528. //
  1529. NtStatus = GetNameFromValue(hKey, VOLATILE_COMPUTERNAME, lpBuffer,
  1530. nSize);
  1531. //
  1532. // The user's buffer wasn't big enough, just return the error.
  1533. //
  1534. if(NtStatus == STATUS_BUFFER_OVERFLOW) {
  1535. SetLastError(ERROR_BUFFER_OVERFLOW);
  1536. ReturnValue = FALSE;
  1537. goto Cleanup;
  1538. }
  1539. if (NT_SUCCESS(NtStatus)) {
  1540. //
  1541. // The volatile copy is already there, just return it
  1542. //
  1543. goto GoodReturn;
  1544. }
  1545. //
  1546. // The volatile key isn't there, try for the non-volatile one
  1547. //
  1548. NtStatus = GetNameFromValue(hKey, NON_VOLATILE_COMPUTERNAME, lpBuffer,
  1549. nSize);
  1550. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1551. //
  1552. // This should never happen! This value should have been created
  1553. // at setup, and protected by an ACL so that only the ADMIN could
  1554. // write to it. Generate an event, and return an error to the
  1555. // caller
  1556. //
  1557. // NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
  1558. //
  1559. // Return a NULL computername
  1560. //
  1561. lpBuffer[0] = L'\0';
  1562. *nSize = 0;
  1563. goto GoodReturn;
  1564. }
  1565. if (!NT_SUCCESS(NtStatus)) {
  1566. //
  1567. // Some other error, return it to the caller
  1568. //
  1569. goto ErrorReturn;
  1570. }
  1571. //
  1572. // Now create the volatile key to "lock this in" until the next boot
  1573. //
  1574. RtlInitUnicodeString(&Class, CLASS_STRING);
  1575. //
  1576. // Turn KeyName into a UNICODE_STRING
  1577. //
  1578. RtlInitUnicodeString(&KeyName, VOLATILE_COMPUTERNAME);
  1579. InitializeObjectAttributes(&ObjectAttributes,
  1580. &KeyName,
  1581. OBJ_CASE_INSENSITIVE,
  1582. hKey,
  1583. NULL
  1584. );
  1585. //
  1586. // Now create the key
  1587. //
  1588. NtStatus = NtCreateKey(&hNewKey,
  1589. KEY_WRITE | KEY_READ,
  1590. &ObjectAttributes,
  1591. 0,
  1592. &Class,
  1593. REG_OPTION_VOLATILE,
  1594. &Disposition);
  1595. if (Disposition == REG_OPENED_EXISTING_KEY) {
  1596. //
  1597. // Someone beat us to this, just get the value they put there
  1598. //
  1599. NtStatus = GetNameFromValue(hKey, VOLATILE_COMPUTERNAME, lpBuffer,
  1600. nSize);
  1601. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1602. //
  1603. // This should never happen! It just told me it existed
  1604. //
  1605. NtStatus = STATUS_UNSUCCESSFUL;
  1606. goto ErrorReturn;
  1607. }
  1608. }
  1609. //
  1610. // Create the value under this key
  1611. //
  1612. RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
  1613. ValueLength = (wcslen(lpBuffer) + 1) * sizeof(WCHAR);
  1614. NtStatus = NtSetValueKey(hNewKey,
  1615. &ValueName,
  1616. 0,
  1617. REG_SZ,
  1618. lpBuffer,
  1619. ValueLength);
  1620. if (!NT_SUCCESS(NtStatus)) {
  1621. goto ErrorReturn;
  1622. }
  1623. goto GoodReturn;
  1624. ErrorReturn:
  1625. //
  1626. // An error was encountered, convert the status and return
  1627. //
  1628. BaseSetLastNTError(NtStatus);
  1629. ReturnValue = FALSE;
  1630. goto Cleanup;
  1631. GoodReturn:
  1632. //
  1633. // Everything went ok, update nSize with the length of the buffer and
  1634. // return
  1635. //
  1636. *nSize = wcslen(lpBuffer);
  1637. ReturnValue = TRUE;
  1638. goto Cleanup;
  1639. Cleanup:
  1640. if (hKey) {
  1641. NtClose(hKey);
  1642. }
  1643. if (hNewKey) {
  1644. NtClose(hNewKey);
  1645. }
  1646. return(ReturnValue);
  1647. }
  1648. BOOL
  1649. WINAPI
  1650. SetComputerNameW (
  1651. LPCWSTR lpComputerName
  1652. )
  1653. /*++
  1654. Routine Description:
  1655. This sets what the computername will be when the system is next booted. This
  1656. does not effect the active computername for the remainder of this boot, nor
  1657. what is returned by GetComputerName before the next system boot.
  1658. Arguments:
  1659. lpComputerName - points to the buffer that is contains the
  1660. null-terminated character string containing the computer name.
  1661. Return Value:
  1662. Returns TRUE on success, FALSE on failure.
  1663. --*/
  1664. {
  1665. NTSTATUS NtStatus;
  1666. UNICODE_STRING KeyName;
  1667. UNICODE_STRING ValueName;
  1668. OBJECT_ATTRIBUTES ObjectAttributes;
  1669. HANDLE hKey = NULL;
  1670. ULONG ValueLength;
  1671. ULONG ComputerNameLength;
  1672. ULONG AnsiComputerNameLength;
  1673. //
  1674. // Validate that the supplied computername is valid (not too long,
  1675. // no incorrect characters, no leading or trailing spaces)
  1676. //
  1677. ComputerNameLength = wcslen(lpComputerName);
  1678. //
  1679. // The name length limitation should be based on ANSI. (LanMan compatibility)
  1680. //
  1681. NtStatus = RtlUnicodeToMultiByteSize(&AnsiComputerNameLength,
  1682. (LPWSTR)lpComputerName,
  1683. ComputerNameLength * sizeof(WCHAR));
  1684. if ((!NT_SUCCESS(NtStatus)) ||
  1685. (AnsiComputerNameLength == 0 )||(AnsiComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
  1686. SetLastError(ERROR_INVALID_PARAMETER);
  1687. return(FALSE);
  1688. }
  1689. //
  1690. // Check for illegal characters; return an error if one is found
  1691. //
  1692. if (wcscspn(lpComputerName, ILLEGAL_NAME_CHARS_STR) < ComputerNameLength) {
  1693. SetLastError(ERROR_INVALID_PARAMETER);
  1694. return(FALSE);
  1695. }
  1696. //
  1697. // Check for leading or trailing spaces
  1698. //
  1699. if (lpComputerName[0] == L' ' ||
  1700. lpComputerName[ComputerNameLength-1] == L' ') {
  1701. SetLastError(ERROR_INVALID_PARAMETER);
  1702. return(FALSE);
  1703. }
  1704. //
  1705. // Open the ComputerName\ComputerName node
  1706. //
  1707. RtlInitUnicodeString(&KeyName, NON_VOLATILE_COMPUTERNAME_NODE);
  1708. InitializeObjectAttributes(&ObjectAttributes,
  1709. &KeyName,
  1710. OBJ_CASE_INSENSITIVE,
  1711. NULL,
  1712. NULL
  1713. );
  1714. NtStatus = NtOpenKey(&hKey, KEY_READ | KEY_WRITE, &ObjectAttributes);
  1715. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  1716. //
  1717. // This should never happen! This key should have been created
  1718. // at setup, and protected by an ACL so that only the ADMIN could
  1719. // write to it. Generate an event, and return a NULL computername.
  1720. //
  1721. // NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
  1722. // (One alternative for this instance would be to actually create the missing
  1723. // entry here -- but we'd have to be sure to get the right ACLs etc, etc.
  1724. SetLastError(ERROR_GEN_FAILURE);
  1725. return(FALSE);
  1726. }
  1727. //
  1728. // Update the value under this key
  1729. //
  1730. RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
  1731. ValueLength = (wcslen(lpComputerName) + 1) * sizeof(WCHAR);
  1732. NtStatus = NtSetValueKey(hKey,
  1733. &ValueName,
  1734. 0,
  1735. REG_SZ,
  1736. (LPWSTR)lpComputerName,
  1737. ValueLength);
  1738. if (!NT_SUCCESS(NtStatus)) {
  1739. BaseSetLastNTError(NtStatus);
  1740. NtClose(hKey);
  1741. return(FALSE);
  1742. }
  1743. NtFlushKey(hKey);
  1744. NtClose(hKey);
  1745. return(TRUE);
  1746. }
  1747. BOOL
  1748. WINAPI
  1749. GetComputerNameExW(
  1750. IN COMPUTER_NAME_FORMAT NameType,
  1751. OUT LPWSTR lpBuffer,
  1752. IN OUT LPDWORD nSize
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. This returns the active computername in a particular format. This is the
  1757. computername when the system was last booted. If this is changed (via
  1758. SetComputerName) it does not take effect until the next system boot.
  1759. Arguments:
  1760. NameType - Possible name formats to return the computer name in:
  1761. ComputerNameNetBIOS - netbios name (compatible with GetComputerName)
  1762. ComputerNameDnsHostname - DNS host name
  1763. ComputerNameDnsDomain - DNS Domain name
  1764. ComputerNameDnsFullyQualified - DNS Fully Qualified (hostname.dnsdomain)
  1765. lpBuffer - Points to the buffer that is to receive the
  1766. null-terminated character string containing the computer name.
  1767. nSize - Specifies the maximum size (in characters) of the buffer. This
  1768. value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
  1769. sufficient room in the buffer for the computer name. The length
  1770. of the string is returned in nSize.
  1771. Return Value:
  1772. TRUE on success, FALSE on failure.
  1773. --*/
  1774. {
  1775. NTSTATUS Status ;
  1776. DWORD ValueLength ;
  1777. DWORD HostLength ;
  1778. DWORD DomainLength ;
  1779. BOOL DontSetReturn = FALSE ;
  1780. COMPUTER_NAME_FORMAT HostNameFormat, DomainNameFormat ;
  1781. if ( NameType >= ComputerNameMax )
  1782. {
  1783. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  1784. return FALSE ;
  1785. }
  1786. if ((nSize==NULL) || ((lpBuffer==NULL) && (*nSize>0))) {
  1787. SetLastError(ERROR_INVALID_PARAMETER);
  1788. return(FALSE);
  1789. }
  1790. //
  1791. // For general names, allow clusters to override the physical name:
  1792. //
  1793. if ( (NameType >= ComputerNameNetBIOS) &&
  1794. (NameType <= ComputerNameDnsFullyQualified ) )
  1795. {
  1796. ValueLength = GetEnvironmentVariableW(
  1797. ClusterNameVars[ NameType ],
  1798. lpBuffer,
  1799. *nSize );
  1800. if ( ValueLength )
  1801. {
  1802. BOOL ReturnValue;
  1803. //
  1804. // ValueLength is the length+NULL of the env. string regardless of
  1805. // how much was copied (gregjohn 1/30/01 note: this isn't the behaivor
  1806. // of the rest of the function, which returns length+NULL on failure
  1807. // and length on success). Indicate how many characters are in the string
  1808. // and if the user's buffer wasn't big enough, return FALSE
  1809. //
  1810. ReturnValue = ( *nSize >= ValueLength ? TRUE : FALSE );
  1811. if ( !ReturnValue ) {
  1812. SetLastError( ERROR_MORE_DATA );
  1813. }
  1814. *nSize = ValueLength ;
  1815. return ReturnValue;
  1816. }
  1817. }
  1818. if ( lpBuffer && (*nSize > 0) )
  1819. {
  1820. lpBuffer[0] = L'\0';
  1821. }
  1822. switch ( NameType )
  1823. {
  1824. case ComputerNameNetBIOS:
  1825. case ComputerNamePhysicalNetBIOS:
  1826. Status = BasepGetNameFromReg(
  1827. VOLATILE_COMPUTERNAME_NODE,
  1828. COMPUTERNAME_VALUE_NAME,
  1829. lpBuffer,
  1830. nSize );
  1831. if ( !NT_SUCCESS( Status ) )
  1832. {
  1833. if ( Status != STATUS_BUFFER_OVERFLOW )
  1834. {
  1835. //
  1836. // Hmm, the value (or key) is missing. Try the non-volatile
  1837. // one.
  1838. //
  1839. Status = BasepGetNameFromReg(
  1840. NON_VOLATILE_COMPUTERNAME_NODE,
  1841. COMPUTERNAME_VALUE_NAME,
  1842. lpBuffer,
  1843. nSize );
  1844. }
  1845. }
  1846. break;
  1847. case ComputerNameDnsHostname:
  1848. case ComputerNamePhysicalDnsHostname:
  1849. Status = BasepGetNameFromReg(
  1850. TCPIP_ROOT,
  1851. TCPIP_HOSTNAME,
  1852. lpBuffer,
  1853. nSize );
  1854. break;
  1855. case ComputerNameDnsDomain:
  1856. case ComputerNamePhysicalDnsDomain:
  1857. //
  1858. // Allow policy to override the domain name from the
  1859. // tcpip key.
  1860. //
  1861. Status = BasepGetNameFromReg(
  1862. TCPIP_POLICY_ROOT,
  1863. TCPIP_POLICY_DOMAINNAME,
  1864. lpBuffer,
  1865. nSize );
  1866. //
  1867. // If no policy read from the tcpip key.
  1868. //
  1869. if ( !NT_SUCCESS( Status ) )
  1870. {
  1871. Status = BasepGetNameFromReg(
  1872. TCPIP_ROOT,
  1873. TCPIP_DOMAINNAME,
  1874. lpBuffer,
  1875. nSize );
  1876. }
  1877. break;
  1878. case ComputerNameDnsFullyQualified:
  1879. case ComputerNamePhysicalDnsFullyQualified:
  1880. //
  1881. // This is the tricky case. We have to construct the name from
  1882. // the two components for the caller.
  1883. //
  1884. //
  1885. // In general, don't set the last status, since we'll end up using
  1886. // the other calls to handle that for us.
  1887. //
  1888. DontSetReturn = TRUE ;
  1889. Status = STATUS_UNSUCCESSFUL ;
  1890. if ( lpBuffer == NULL )
  1891. {
  1892. //
  1893. // If this is just the computation call, quickly do the
  1894. // two components
  1895. //
  1896. HostLength = DomainLength = 0 ;
  1897. GetComputerNameExW( ComputerNameDnsHostname, NULL, &HostLength );
  1898. if ( GetLastError() == ERROR_MORE_DATA )
  1899. {
  1900. GetComputerNameExW( ComputerNameDnsDomain, NULL, &DomainLength );
  1901. if ( GetLastError() == ERROR_MORE_DATA )
  1902. {
  1903. //
  1904. // Simply add. Note that since both account for a
  1905. // null terminator, the '.' that goes between them is
  1906. // covered.
  1907. //
  1908. *nSize = HostLength + DomainLength ;
  1909. Status = STATUS_BUFFER_OVERFLOW ;
  1910. DontSetReturn = FALSE ;
  1911. }
  1912. }
  1913. }
  1914. else
  1915. {
  1916. HostLength = *nSize ;
  1917. if ( GetComputerNameExW( ComputerNameDnsHostname,
  1918. lpBuffer,
  1919. &HostLength ) )
  1920. {
  1921. HostLength += 1; // Add in the zero character (or . depending on perspective)
  1922. lpBuffer[ HostLength - 1 ] = L'.';
  1923. DomainLength = *nSize - HostLength ;
  1924. if (GetComputerNameExW( ComputerNameDnsDomain,
  1925. &lpBuffer[ HostLength ],
  1926. &DomainLength ) )
  1927. {
  1928. Status = STATUS_SUCCESS ;
  1929. if ( DomainLength == 0 )
  1930. {
  1931. lpBuffer[ HostLength - 1 ] = L'\0';
  1932. HostLength-- ;
  1933. }
  1934. else if ( ( DomainLength == 1 ) &&
  1935. ( lpBuffer[ HostLength ] == L'.' ) )
  1936. {
  1937. //
  1938. // Legally, the domain name can be a single
  1939. // dot '.', indicating that this host is part
  1940. // of the root domain. An odd case, to be sure,
  1941. // but needs to be handled. Since we've already
  1942. // stuck a dot separator in the result string,
  1943. // get rid of this one, and adjust the values
  1944. // accordingly.
  1945. //
  1946. lpBuffer[ HostLength ] = L'\0' ;
  1947. DomainLength = 0 ;
  1948. }
  1949. *nSize = HostLength + DomainLength ;
  1950. DontSetReturn = TRUE ;
  1951. }
  1952. else if ( GetLastError() == ERROR_MORE_DATA )
  1953. {
  1954. //
  1955. // Simply add. Note that since both account for a
  1956. // null terminator, the '.' that goes between them is
  1957. // covered.
  1958. //
  1959. *nSize = HostLength + DomainLength ;
  1960. Status = STATUS_BUFFER_OVERFLOW ;
  1961. DontSetReturn = FALSE ;
  1962. }
  1963. else
  1964. {
  1965. //
  1966. // Other error from trying to get the DNS Domain name.
  1967. // Let the error from the call trickle back.
  1968. //
  1969. *nSize = 0 ;
  1970. Status = STATUS_UNSUCCESSFUL ;
  1971. DontSetReturn = TRUE ;
  1972. }
  1973. }
  1974. else if ( GetLastError() == ERROR_MORE_DATA )
  1975. {
  1976. DomainLength = 0;
  1977. GetComputerNameExW( ComputerNameDnsDomain, NULL, &DomainLength );
  1978. if ( GetLastError() == ERROR_MORE_DATA )
  1979. {
  1980. //
  1981. // Simply add. Note that since both account for a
  1982. // null terminator, the '.' that goes between them is
  1983. // covered.
  1984. //
  1985. *nSize = HostLength + DomainLength ;
  1986. Status = STATUS_BUFFER_OVERFLOW ;
  1987. DontSetReturn = FALSE ;
  1988. }
  1989. }
  1990. else
  1991. {
  1992. //
  1993. // Other error from trying to get the DNS Hostname.
  1994. // Let the error from the call trickle back.
  1995. //
  1996. *nSize = 0 ;
  1997. Status = STATUS_UNSUCCESSFUL ;
  1998. DontSetReturn = TRUE ;
  1999. }
  2000. }
  2001. break;
  2002. }
  2003. if ( !NT_SUCCESS( Status ) )
  2004. {
  2005. if ( !DontSetReturn )
  2006. {
  2007. BaseSetLastNTError( Status );
  2008. }
  2009. return FALSE ;
  2010. }
  2011. return TRUE ;
  2012. }
  2013. BOOL
  2014. WINAPI
  2015. SetComputerNameExW(
  2016. IN COMPUTER_NAME_FORMAT NameType,
  2017. IN LPCWSTR lpBuffer
  2018. )
  2019. /*++
  2020. Routine Description:
  2021. This sets what the computername will be when the system is next booted. This
  2022. does not effect the active computername for the remainder of this boot, nor
  2023. what is returned by GetComputerName before the next system boot.
  2024. Arguments:
  2025. NameType - Name to set for the system
  2026. lpComputerName - points to the buffer that is contains the
  2027. null-terminated character string containing the computer name.
  2028. Return Value:
  2029. Returns TRUE on success, FALSE on failure.
  2030. --*/
  2031. {
  2032. ULONG Length ;
  2033. //
  2034. // Validate name:
  2035. //
  2036. if ( !lpBuffer )
  2037. {
  2038. SetLastError( ERROR_INVALID_PARAMETER );
  2039. return FALSE ;
  2040. }
  2041. Length = wcslen( lpBuffer );
  2042. if ( Length )
  2043. {
  2044. if ( ( lpBuffer[0] == L' ') ||
  2045. ( lpBuffer[ Length - 1 ] == L' ' ) )
  2046. {
  2047. SetLastError( ERROR_INVALID_PARAMETER );
  2048. return FALSE ;
  2049. }
  2050. }
  2051. if (wcscspn(lpBuffer, ILLEGAL_NAME_CHARS_STR) < Length) {
  2052. SetLastError(ERROR_INVALID_PARAMETER);
  2053. return(FALSE);
  2054. }
  2055. switch ( NameType )
  2056. {
  2057. case ComputerNamePhysicalNetBIOS:
  2058. return BaseSetNetbiosName( lpBuffer );
  2059. case ComputerNamePhysicalDnsHostname:
  2060. return BaseSetDnsName( lpBuffer );
  2061. case ComputerNamePhysicalDnsDomain:
  2062. return BaseSetDnsDomain( lpBuffer );
  2063. default:
  2064. SetLastError( ERROR_INVALID_PARAMETER );
  2065. return FALSE ;
  2066. }
  2067. }
  2068. //
  2069. // ANSI APIs
  2070. //
  2071. BOOL
  2072. WINAPI
  2073. GetComputerNameA (
  2074. LPSTR lpBuffer,
  2075. LPDWORD nSize
  2076. )
  2077. /*++
  2078. Routine Description:
  2079. This returns the active computername. This is the computername when the
  2080. system was last booted. If this is changed (via SetComputerName) it does
  2081. not take effect until the next system boot.
  2082. Arguments:
  2083. lpBuffer - Points to the buffer that is to receive the
  2084. null-terminated character string containing the computer name.
  2085. nSize - Specifies the maximum size (in characters) of the buffer. This
  2086. value should be set to at least MAX_COMPUTERNAME_LENGTH to allow
  2087. sufficient room in the buffer for the computer name. The length of
  2088. the string is returned in nSize.
  2089. Return Value:
  2090. TRUE on success, FALSE on failure.
  2091. --*/
  2092. {
  2093. UNICODE_STRING UnicodeString;
  2094. ANSI_STRING AnsiString;
  2095. LPWSTR UnicodeBuffer;
  2096. ULONG AnsiSize;
  2097. ULONG UnicodeSize;
  2098. //
  2099. // Work buffer needs to be twice the size of the user's buffer
  2100. //
  2101. UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
  2102. if (!UnicodeBuffer) {
  2103. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2104. return(FALSE);
  2105. }
  2106. //
  2107. // Set up an ANSI_STRING that points to the user's buffer
  2108. //
  2109. AnsiString.MaximumLength = (USHORT) *nSize;
  2110. AnsiString.Length = 0;
  2111. AnsiString.Buffer = lpBuffer;
  2112. //
  2113. // Call the UNICODE version to do the work
  2114. //
  2115. UnicodeSize = *nSize ;
  2116. if (!GetComputerNameW(UnicodeBuffer, &UnicodeSize)) {
  2117. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  2118. return(FALSE);
  2119. }
  2120. //
  2121. // Find out the required size of the ANSI buffer and validate it against
  2122. // the passed in buffer size
  2123. //
  2124. RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
  2125. AnsiSize = RtlUnicodeStringToAnsiSize(&UnicodeString);
  2126. if (AnsiSize > *nSize) {
  2127. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  2128. BaseSetLastNTError( STATUS_BUFFER_OVERFLOW );
  2129. *nSize = AnsiSize + 1 ;
  2130. return(FALSE);
  2131. }
  2132. //
  2133. // Now convert back to ANSI for the caller
  2134. //
  2135. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  2136. *nSize = AnsiString.Length;
  2137. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  2138. return(TRUE);
  2139. }
  2140. BOOL
  2141. WINAPI
  2142. SetComputerNameA (
  2143. LPCSTR lpComputerName
  2144. )
  2145. /*++
  2146. Routine Description:
  2147. This sets what the computername will be when the system is next booted. This
  2148. does not effect the active computername for the remainder of this boot, nor
  2149. what is returned by GetComputerName before the next system boot.
  2150. Arguments:
  2151. lpComputerName - points to the buffer that is contains the
  2152. null-terminated character string containing the computer name.
  2153. Return Value:
  2154. Returns TRUE on success, FALSE on failure.
  2155. --*/
  2156. {
  2157. NTSTATUS NtStatus;
  2158. BOOL ReturnValue;
  2159. UNICODE_STRING UnicodeString;
  2160. ANSI_STRING AnsiString;
  2161. ULONG ComputerNameLength;
  2162. //
  2163. // Validate that the supplied computername is valid (not too long,
  2164. // no incorrect characters, no leading or trailing spaces)
  2165. //
  2166. ComputerNameLength = strlen(lpComputerName);
  2167. if ((ComputerNameLength == 0 )||(ComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
  2168. SetLastError(ERROR_INVALID_PARAMETER);
  2169. return(FALSE);
  2170. }
  2171. RtlInitAnsiString(&AnsiString, lpComputerName);
  2172. NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString,
  2173. TRUE);
  2174. if (!NT_SUCCESS(NtStatus)) {
  2175. BaseSetLastNTError(NtStatus);
  2176. return(FALSE);
  2177. }
  2178. ReturnValue = SetComputerNameW((LPCWSTR)UnicodeString.Buffer);
  2179. RtlFreeUnicodeString(&UnicodeString);
  2180. return(ReturnValue);
  2181. }
  2182. BOOL
  2183. WINAPI
  2184. GetComputerNameExA(
  2185. IN COMPUTER_NAME_FORMAT NameType,
  2186. OUT LPSTR lpBuffer,
  2187. IN OUT LPDWORD nSize
  2188. )
  2189. /*++
  2190. Routine Description:
  2191. This returns the active computername in a particular format. This is the
  2192. computername when the system was last booted. If this is changed (via
  2193. SetComputerName) it does not take effect until the next system boot.
  2194. Arguments:
  2195. NameType - Possible name formats to return the computer name in:
  2196. ComputerNameNetBIOS - netbios name (compatible with GetComputerName)
  2197. ComputerNameDnsHostname - DNS host name
  2198. ComputerNameDnsDomain - DNS Domain name
  2199. ComputerNameDnsFullyQualified - DNS Fully Qualified (hostname.dnsdomain)
  2200. lpBuffer - Points to the buffer that is to receive the
  2201. null-terminated character string containing the computer name.
  2202. nSize - Specifies the maximum size (in characters) of the buffer. This
  2203. value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
  2204. sufficient room in the buffer for the computer name. The length
  2205. of the string is returned in nSize.
  2206. Return Value:
  2207. TRUE on success, FALSE on failure.
  2208. --*/
  2209. {
  2210. LPWSTR UnicodeBuffer;
  2211. //
  2212. // Validate Input
  2213. //
  2214. if ((nSize==NULL) || ((lpBuffer==NULL) && (*nSize>0))) {
  2215. SetLastError(ERROR_INVALID_PARAMETER);
  2216. return(FALSE);
  2217. }
  2218. //
  2219. // Work buffer needs to be twice the size of the user's buffer
  2220. //
  2221. UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
  2222. if (!UnicodeBuffer) {
  2223. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2224. return(FALSE);
  2225. }
  2226. //
  2227. // Call the UNICODE version to do the work
  2228. //
  2229. if ( !GetComputerNameExW(NameType, UnicodeBuffer, nSize) ) {
  2230. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  2231. return(FALSE);
  2232. }
  2233. //
  2234. // Now convert back to ANSI for the caller
  2235. // Note: Since we passed the above if statement,
  2236. // GetComputerNameExW succeeded, and set *nSize to the number of
  2237. // characters in the string (like wcslen). We need to convert
  2238. // all these characters and the trailing NULL, so inc *nSize for
  2239. // the conversion call.
  2240. //
  2241. WideCharToMultiByte(CP_ACP,
  2242. 0,
  2243. UnicodeBuffer,
  2244. *nSize+1,
  2245. lpBuffer,
  2246. (*nSize+1) * sizeof(CHAR),
  2247. NULL,
  2248. NULL);
  2249. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  2250. return(TRUE);
  2251. }
  2252. BOOL
  2253. WINAPI
  2254. SetComputerNameExA(
  2255. IN COMPUTER_NAME_FORMAT NameType,
  2256. IN LPCSTR lpBuffer
  2257. )
  2258. /*++
  2259. Routine Description:
  2260. This sets what the computername will be when the system is next booted. This
  2261. does not effect the active computername for the remainder of this boot, nor
  2262. what is returned by GetComputerName before the next system boot.
  2263. Arguments:
  2264. NameType - Name to set for the system
  2265. lpComputerName - points to the buffer that is contains the
  2266. null-terminated character string containing the computer name.
  2267. Return Value:
  2268. Returns TRUE on success, FALSE on failure.
  2269. --*/
  2270. {
  2271. NTSTATUS NtStatus;
  2272. BOOL ReturnValue;
  2273. UNICODE_STRING UnicodeString;
  2274. ANSI_STRING AnsiString;
  2275. RtlInitAnsiString(&AnsiString, lpBuffer);
  2276. NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString,
  2277. TRUE);
  2278. if (!NT_SUCCESS(NtStatus)) {
  2279. BaseSetLastNTError(NtStatus);
  2280. return(FALSE);
  2281. }
  2282. ReturnValue = SetComputerNameExW(NameType, (LPCWSTR)UnicodeString.Buffer );
  2283. RtlFreeUnicodeString(&UnicodeString);
  2284. return(ReturnValue);
  2285. }
  2286. DWORD
  2287. WINAPI
  2288. AddLocalAlternateComputerNameW(
  2289. LPCWSTR lpDnsFQHostname,
  2290. ULONG ulFlags
  2291. )
  2292. /*++
  2293. Routine Description:
  2294. This sets an alternate computer name for the computer to begin to
  2295. respond to.
  2296. Arguments:
  2297. lpDnsFQHostname - The alternate name to add (in ComputerNameDnsFullyQualified Format)
  2298. ulFlags - TBD
  2299. Return Value:
  2300. Returns ERROR
  2301. --*/
  2302. {
  2303. NTSTATUS status = STATUS_SUCCESS;
  2304. DWORD err = ERROR_SUCCESS;
  2305. LPWSTR lpNetBiosCompName = NULL;
  2306. ULONG ulNetBiosCompNameSize = 0;
  2307. LPWSTR lpHostname = BaseParseDnsName(lpDnsFQHostname,DNS_HOSTNAME);
  2308. //
  2309. // validate input
  2310. //
  2311. if ((lpDnsFQHostname==NULL) || (!BaseValidateFlags(ulFlags)) || (!BaseValidateDnsNames(lpHostname))) {
  2312. if (lpHostname) {
  2313. RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
  2314. }
  2315. return ERROR_INVALID_PARAMETER;
  2316. }
  2317. // get write lock?
  2318. status = BaseAddMultiNameInReg(
  2319. DNSCACHE_ROOT,
  2320. DNS_ALT_HOSTNAME,
  2321. lpDnsFQHostname);
  2322. err = RtlNtStatusToDosError(status);
  2323. if (err==ERROR_SUCCESS) {
  2324. // get NetBios name (use DNSHostNameToComputerNameW) and add that to reg for OptionalNames
  2325. if (!DnsHostnameToComputerNameW(
  2326. lpDnsFQHostname,
  2327. NULL,
  2328. &ulNetBiosCompNameSize)) {
  2329. err = GetLastError();
  2330. }
  2331. if (err==ERROR_MORE_DATA) {
  2332. // bug in DNSHostname, returns a size 1 character too small (forgets null)
  2333. // update when bug is fixed...
  2334. ulNetBiosCompNameSize += 1;
  2335. lpNetBiosCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), ulNetBiosCompNameSize * sizeof(WCHAR));
  2336. if (lpNetBiosCompName==NULL) {
  2337. err = ERROR_NOT_ENOUGH_MEMORY;
  2338. }
  2339. else {
  2340. if (!DnsHostnameToComputerNameW(lpDnsFQHostname,
  2341. lpNetBiosCompName,
  2342. &ulNetBiosCompNameSize)) {
  2343. err = GetLastError();
  2344. }
  2345. else {
  2346. if (!BaseSetAltNetBiosName(lpNetBiosCompName)) {
  2347. err = GetLastError();
  2348. }
  2349. }
  2350. RtlFreeHeap(RtlProcessHeap(), 0, lpNetBiosCompName);
  2351. }
  2352. }
  2353. if (err!=ERROR_SUCCESS) {
  2354. // remove multi name in reg
  2355. // rollback?
  2356. }
  2357. }
  2358. if (lpHostname) {
  2359. RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
  2360. }
  2361. // release write lock?
  2362. return RtlNtStatusToDosError(status);
  2363. }
  2364. DWORD
  2365. WINAPI
  2366. AddLocalAlternateComputerNameA(
  2367. LPCSTR lpDnsFQHostname,
  2368. ULONG ulFlags
  2369. )
  2370. {
  2371. LPWSTR lpDnsFQHostnameW = NULL;
  2372. DWORD err = ERROR_SUCCESS;
  2373. if (lpDnsFQHostname==NULL) {
  2374. return ERROR_INVALID_PARAMETER;
  2375. }
  2376. err = BaseMultiByteToWideCharWithAlloc(lpDnsFQHostname, &lpDnsFQHostnameW);
  2377. if (err==ERROR_SUCCESS) {
  2378. err = AddLocalAlternateComputerNameW(lpDnsFQHostnameW, ulFlags);
  2379. }
  2380. BaseConvertCharFree((VOID *)lpDnsFQHostnameW);
  2381. return err;
  2382. }
  2383. DWORD
  2384. WINAPI
  2385. RemoveLocalAlternateComputerNameW(
  2386. LPCWSTR lpAltDnsFQHostname,
  2387. ULONG ulFlags
  2388. )
  2389. /*++
  2390. Routine Description:
  2391. Remove an alternate computer name.
  2392. Arguments:
  2393. lpAltDnsFQHostname - The alternate name to remove(in ComputerNameDnsFullyQualified Format)
  2394. ulFlags - TBD
  2395. Return Value:
  2396. Returns ERROR
  2397. --*/
  2398. {
  2399. DWORD err = ERROR_SUCCESS;
  2400. NTSTATUS NtStatus = STATUS_SUCCESS;
  2401. LPWSTR lpAltNetBiosCompName = NULL;
  2402. ULONG cchAltNetBiosCompName = 0;
  2403. if ((!BaseValidateFlags(ulFlags)) || (lpAltDnsFQHostname==NULL)) {
  2404. return ERROR_INVALID_PARAMETER;
  2405. }
  2406. // aquire a write lock?
  2407. NtStatus = BaseRemoveMultiNameFromReg(DNSCACHE_ROOT, DNS_ALT_HOSTNAME, lpAltDnsFQHostname);
  2408. err = RtlNtStatusToDosError(NtStatus);
  2409. if (err==ERROR_SUCCESS) {
  2410. if (!DnsHostnameToComputerNameW(
  2411. lpAltDnsFQHostname,
  2412. NULL,
  2413. &cchAltNetBiosCompName)) {
  2414. err = GetLastError();
  2415. }
  2416. if (err==ERROR_MORE_DATA) {
  2417. // bug in DNSHostname, returns a size 1 character too small (forgets null)
  2418. cchAltNetBiosCompName += 1;
  2419. lpAltNetBiosCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchAltNetBiosCompName * sizeof(WCHAR));
  2420. if (lpAltNetBiosCompName==NULL) {
  2421. err = ERROR_NOT_ENOUGH_MEMORY;
  2422. }
  2423. else {
  2424. err = ERROR_SUCCESS;
  2425. if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname,
  2426. lpAltNetBiosCompName,
  2427. &cchAltNetBiosCompName)) {
  2428. err = GetLastError();
  2429. } else if (BaseIsNetBiosNameInUse(lpAltNetBiosCompName)) {
  2430. // do nothing, this name is still being used by another AltDnsHostname ...
  2431. } else if (!BaseRemoveAltNetBiosName(lpAltNetBiosCompName)) {
  2432. err = GetLastError();
  2433. }
  2434. RtlFreeHeap(RtlProcessHeap(), 0, lpAltNetBiosCompName);
  2435. }
  2436. }
  2437. }
  2438. // release write lock?
  2439. return err;
  2440. }
  2441. DWORD
  2442. WINAPI
  2443. RemoveLocalAlternateComputerNameA(
  2444. LPCSTR lpAltDnsFQHostname,
  2445. ULONG ulFlags
  2446. )
  2447. {
  2448. LPWSTR lpAltDnsFQHostnameW = NULL;
  2449. DWORD err = ERROR_SUCCESS;
  2450. if (lpAltDnsFQHostname==NULL) {
  2451. return ERROR_INVALID_PARAMETER;
  2452. }
  2453. err = BaseMultiByteToWideCharWithAlloc(lpAltDnsFQHostname, &lpAltDnsFQHostnameW);
  2454. if (err==ERROR_SUCCESS) {
  2455. err = RemoveLocalAlternateComputerNameW(lpAltDnsFQHostnameW, ulFlags);
  2456. }
  2457. BaseConvertCharFree((VOID *)lpAltDnsFQHostnameW);
  2458. return err;
  2459. }
  2460. DWORD
  2461. WINAPI
  2462. SetLocalPrimaryComputerNameW(
  2463. LPCWSTR lpAltDnsFQHostname,
  2464. ULONG ulFlags
  2465. )
  2466. /*++
  2467. Routine Description:
  2468. Set the computer name to the inputed altCompName
  2469. Arguments:
  2470. lpAltDnsFQHostname - The name to set the computer to (in ComputerNameDnsFullyQualified Format)
  2471. ulFlags - TBD
  2472. Return Value:
  2473. Returns ERROR
  2474. --*/
  2475. {
  2476. DWORD err = ERROR_SUCCESS;
  2477. ULONG cchNetBiosName = 0;
  2478. LPWSTR lpNetBiosName = NULL;
  2479. ULONG cchCompName = 0;
  2480. LPWSTR lpCompName = NULL;
  2481. LPWSTR lpHostname = BaseParseDnsName(lpAltDnsFQHostname, DNS_HOSTNAME);
  2482. LPWSTR lpDomainName = BaseParseDnsName(lpAltDnsFQHostname, DNS_DOMAINNAME);
  2483. if ((lpAltDnsFQHostname==NULL) || (!BaseValidateFlags(ulFlags))) {
  2484. return ERROR_INVALID_PARAMETER;
  2485. }
  2486. // aquire a write lock?
  2487. // check to see that the given name is a valid alternate dns hostname
  2488. if (!BaseIsAltDnsFQHostname(lpAltDnsFQHostname)) {
  2489. if (lpHostname) {
  2490. RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
  2491. }
  2492. if (lpDomainName) {
  2493. RtlFreeHeap(RtlProcessHeap(), 0, lpDomainName);
  2494. }
  2495. return ERROR_INVALID_PARAMETER;
  2496. }
  2497. // get the current net bios name and add it to the alternate names
  2498. if (!GetComputerNameExW(ComputerNamePhysicalNetBIOS, NULL, &cchNetBiosName)) {
  2499. err = GetLastError();
  2500. }
  2501. if (err==ERROR_MORE_DATA) {
  2502. lpNetBiosName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchNetBiosName*sizeof(WCHAR));
  2503. if (lpNetBiosName==NULL) {
  2504. err = ERROR_NOT_ENOUGH_MEMORY;
  2505. }
  2506. else if (!GetComputerNameExW(ComputerNamePhysicalNetBIOS, lpNetBiosName, &cchNetBiosName)) {
  2507. err = GetLastError();
  2508. }
  2509. else if (!BaseSetAltNetBiosName(lpNetBiosName)) {
  2510. err = GetLastError();
  2511. }
  2512. else {
  2513. err = ERROR_SUCCESS;
  2514. }
  2515. if (lpNetBiosName) {
  2516. RtlFreeHeap(RtlProcessHeap(), 0, lpNetBiosName);
  2517. }
  2518. }
  2519. if (err==ERROR_SUCCESS) {
  2520. // add the physical dnsname to the list of alternate hostnames...
  2521. if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, NULL, &cchCompName)) {
  2522. err = GetLastError();
  2523. }
  2524. if (err==ERROR_MORE_DATA) {
  2525. lpCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchCompName*sizeof(WCHAR));
  2526. if (lpCompName==NULL) {
  2527. err = ERROR_NOT_ENOUGH_MEMORY;
  2528. }
  2529. else if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpCompName, &cchCompName)) {
  2530. err = GetLastError();
  2531. }
  2532. else if (!BaseSetAltDnsFQHostname(lpCompName)) {
  2533. err = GetLastError();
  2534. }
  2535. else {
  2536. err = ERROR_SUCCESS;
  2537. }
  2538. if (lpCompName) {
  2539. RtlFreeHeap(RtlProcessHeap(), 0, lpCompName);
  2540. }
  2541. }
  2542. }
  2543. // set the new physical dns hostname
  2544. if (err==ERROR_SUCCESS) {
  2545. if (!SetComputerNameExW(ComputerNamePhysicalDnsHostname, lpHostname)) {
  2546. err = GetLastError();
  2547. }
  2548. }
  2549. if (err==ERROR_SUCCESS) {
  2550. if (!SetComputerNameExW(ComputerNamePhysicalDnsDomain, lpDomainName)) {
  2551. err = GetLastError();
  2552. }
  2553. }
  2554. // remove the alternate name (now primary) from the alternate lists
  2555. if (err==ERROR_SUCCESS) {
  2556. err = RemoveLocalAlternateComputerNameW(lpAltDnsFQHostname, 0);
  2557. }
  2558. if (lpHostname) {
  2559. RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
  2560. }
  2561. if (lpDomainName) {
  2562. RtlFreeHeap(RtlProcessHeap(), 0, lpDomainName);
  2563. }
  2564. // release write lock?
  2565. return err;
  2566. }
  2567. DWORD
  2568. WINAPI
  2569. SetLocalPrimaryComputerNameA(
  2570. LPCSTR lpAltDnsFQHostname,
  2571. ULONG ulFlags
  2572. )
  2573. {
  2574. LPWSTR lpAltDnsFQHostnameW = NULL;
  2575. DWORD err = ERROR_SUCCESS;
  2576. if (lpAltDnsFQHostname==NULL) {
  2577. return ERROR_INVALID_PARAMETER;
  2578. }
  2579. err = BaseMultiByteToWideCharWithAlloc(lpAltDnsFQHostname, &lpAltDnsFQHostnameW);
  2580. if (err == ERROR_SUCCESS) {
  2581. err = SetLocalPrimaryComputerNameW(lpAltDnsFQHostnameW, ulFlags);
  2582. }
  2583. BaseConvertCharFree((VOID *)lpAltDnsFQHostnameW);
  2584. return err;
  2585. }
  2586. DWORD
  2587. WINAPI
  2588. EnumerateLocalComputerNamesW(
  2589. COMPUTER_NAME_TYPE NameType,
  2590. ULONG ulFlags,
  2591. LPWSTR lpDnsFQHostnames,
  2592. LPDWORD nSize
  2593. )
  2594. /*++
  2595. Routine Description:
  2596. Returns the value of the computer's names requested.
  2597. Arguments:
  2598. NameType - Which of the computer's names are requested
  2599. PrimaryComputerName - Similar to GetComputerEx(ComputerNamePhysicalNetBios, ...
  2600. AlternateComputerNames - All known alt names
  2601. AllComputerNames - All of the above
  2602. ulFlags - TBD
  2603. lpBuffer - Buffer to hold returned names concatenated together, and trailed with a NULL
  2604. nSize - Size of buffer to hold returned names.
  2605. Return Value:
  2606. Returns ERROR
  2607. --*/
  2608. {
  2609. DWORD err = ERROR_SUCCESS;
  2610. DWORD SizePrimary = 0;
  2611. DWORD SizeAlternate = 0;
  2612. LPWSTR lpTempCompNames = NULL;
  2613. if ((!BaseValidateFlags(ulFlags)) || (NameType>=ComputerNameTypeMax) || (NameType<PrimaryComputerName)) {
  2614. return ERROR_INVALID_PARAMETER;
  2615. }
  2616. // get read lock?
  2617. switch(NameType) {
  2618. case PrimaryComputerName:
  2619. if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpDnsFQHostnames, nSize)) {
  2620. err = GetLastError();
  2621. }
  2622. break;
  2623. case AlternateComputerNames:
  2624. if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
  2625. err = ERROR_INVALID_PARAMETER;
  2626. }
  2627. else {
  2628. err = BaseEnumAltDnsFQHostnames(lpDnsFQHostnames, nSize);
  2629. }
  2630. break;
  2631. case AllComputerNames:
  2632. if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
  2633. err = ERROR_INVALID_PARAMETER;
  2634. }
  2635. else {
  2636. SizePrimary = *nSize;
  2637. lpTempCompNames = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
  2638. if (lpTempCompNames==NULL) {
  2639. err = ERROR_NOT_ENOUGH_MEMORY;
  2640. break;
  2641. }
  2642. // Get primary name
  2643. if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpTempCompNames, &SizePrimary)) {
  2644. err = GetLastError();
  2645. }
  2646. // on success, holds the number of characters copied into lpTempCompNames NOT counting NULL
  2647. // on failure, holds the space needed to copy in, (num characters PLUS NULL)
  2648. if (err==ERROR_SUCCESS) {
  2649. SizeAlternate = *nSize - (SizePrimary + 1);
  2650. err = BaseEnumAltDnsFQHostnames(lpTempCompNames+SizePrimary+1, &SizeAlternate);
  2651. *nSize = SizePrimary + 1 + SizeAlternate;
  2652. if (err==ERROR_SUCCESS) {
  2653. memcpy(lpDnsFQHostnames, lpTempCompNames, (*nSize+1)*sizeof(WCHAR));
  2654. }
  2655. }
  2656. else if (err==ERROR_MORE_DATA) {
  2657. // return total size required
  2658. SizeAlternate = 0;
  2659. err = BaseEnumAltDnsFQHostnames(NULL, &SizeAlternate);
  2660. if (err==ERROR_SUCCESS) {
  2661. // no alt names exist, keep ERROR_MORE_DATA to return to client
  2662. err = ERROR_MORE_DATA;
  2663. }
  2664. *nSize = SizePrimary + SizeAlternate;
  2665. }
  2666. RtlFreeHeap(RtlProcessHeap(), 0, lpTempCompNames);
  2667. }
  2668. break;
  2669. default:
  2670. err = ERROR_INVALID_PARAMETER;
  2671. break;
  2672. }
  2673. // release read lock?
  2674. return err;
  2675. }
  2676. DWORD
  2677. WINAPI
  2678. EnumerateLocalComputerNamesA(
  2679. COMPUTER_NAME_TYPE NameType,
  2680. ULONG ulFlags,
  2681. LPSTR lpDnsFQHostnames,
  2682. LPDWORD nSize
  2683. )
  2684. {
  2685. DWORD err = ERROR_SUCCESS;
  2686. LPWSTR lpDnsFQHostnamesW = NULL;
  2687. //
  2688. // Validate Input
  2689. //
  2690. if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
  2691. return ERROR_INVALID_PARAMETER;
  2692. }
  2693. if (lpDnsFQHostnames!=NULL) {
  2694. lpDnsFQHostnamesW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
  2695. if (lpDnsFQHostnamesW==NULL) {
  2696. err = ERROR_NOT_ENOUGH_MEMORY;
  2697. }
  2698. }
  2699. if (err==ERROR_SUCCESS) {
  2700. err = EnumerateLocalComputerNamesW(NameType, ulFlags, lpDnsFQHostnamesW, nSize);
  2701. }
  2702. if (err==ERROR_SUCCESS) {
  2703. if (!WideCharToMultiByte(CP_ACP, 0, lpDnsFQHostnamesW, *nSize+1,
  2704. lpDnsFQHostnames, (*nSize+1)* sizeof(CHAR), NULL, NULL)) {
  2705. err = GetLastError();
  2706. }
  2707. }
  2708. if (lpDnsFQHostnamesW) {
  2709. RtlFreeHeap(RtlProcessHeap(), 0, lpDnsFQHostnamesW);
  2710. }
  2711. return err;
  2712. }
  2713. BOOL
  2714. WINAPI
  2715. DnsHostnameToComputerNameW(
  2716. IN LPCWSTR Hostname,
  2717. OUT LPWSTR ComputerName,
  2718. IN OUT LPDWORD nSize)
  2719. /*++
  2720. Routine Description:
  2721. This routine will convert a DNS Hostname to a Win32 Computer Name.
  2722. Arguments:
  2723. Hostname - DNS Hostname (any length)
  2724. ComputerName - Win32 Computer Name (max length of MAX_COMPUTERNAME_LENGTH)
  2725. nSize - On input, size of the buffer pointed to by ComputerName. On output,
  2726. size of the Computer Name, in characters.
  2727. Return Value:
  2728. Returns TRUE on success, FALSE on failure.
  2729. --*/
  2730. {
  2731. WCHAR CompName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  2732. DWORD Size = MAX_COMPUTERNAME_LENGTH + 1 ;
  2733. UNICODE_STRING CompName_U ;
  2734. UNICODE_STRING Hostname_U ;
  2735. NTSTATUS Status ;
  2736. BOOL Ret ;
  2737. CompName[0] = L'\0';
  2738. CompName_U.Buffer = CompName ;
  2739. CompName_U.Length = 0 ;
  2740. CompName_U.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR );
  2741. RtlInitUnicodeString( &Hostname_U, Hostname );
  2742. Status = RtlDnsHostNameToComputerName( &CompName_U,
  2743. &Hostname_U,
  2744. FALSE );
  2745. if ( NT_SUCCESS( Status ) )
  2746. {
  2747. if ( *nSize >= CompName_U.Length / sizeof(WCHAR) + 1 )
  2748. {
  2749. RtlCopyMemory( ComputerName,
  2750. CompName_U.Buffer,
  2751. CompName_U.Length );
  2752. ComputerName[ CompName_U.Length / sizeof( WCHAR ) ] = L'\0';
  2753. Ret = TRUE ;
  2754. }
  2755. else
  2756. {
  2757. BaseSetLastNTError( STATUS_BUFFER_OVERFLOW );
  2758. Ret = FALSE ;
  2759. }
  2760. //
  2761. // returns the count of characters
  2762. //
  2763. *nSize = CompName_U.Length / sizeof( WCHAR );
  2764. }
  2765. else
  2766. {
  2767. BaseSetLastNTError( Status );
  2768. Ret = FALSE ;
  2769. }
  2770. return Ret ;
  2771. }
  2772. BOOL
  2773. WINAPI
  2774. DnsHostnameToComputerNameA(
  2775. IN LPCSTR Hostname,
  2776. OUT LPSTR ComputerName,
  2777. IN OUT LPDWORD nSize)
  2778. /*++
  2779. Routine Description:
  2780. This routine will convert a DNS Hostname to a Win32 Computer Name.
  2781. Arguments:
  2782. Hostname - DNS Hostname (any length)
  2783. ComputerName - Win32 Computer Name (max length of MAX_COMPUTERNAME_LENGTH)
  2784. nSize - On input, size of the buffer pointed to by ComputerName. On output,
  2785. size of the Computer Name, in characters.
  2786. Return Value:
  2787. Returns TRUE on success, FALSE on failure.
  2788. --*/
  2789. {
  2790. WCHAR CompName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  2791. DWORD Size = MAX_COMPUTERNAME_LENGTH + 1;
  2792. BOOL Ret ;
  2793. UNICODE_STRING CompName_U ;
  2794. UNICODE_STRING Hostname_U ;
  2795. NTSTATUS Status ;
  2796. ANSI_STRING CompName_A ;
  2797. Status = RtlCreateUnicodeStringFromAsciiz( &Hostname_U,
  2798. Hostname );
  2799. if ( NT_SUCCESS( Status ) )
  2800. {
  2801. CompName[0] = L'\0';
  2802. CompName_U.Buffer = CompName ;
  2803. CompName_U.Length = 0 ;
  2804. CompName_U.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR );
  2805. Status = RtlDnsHostNameToComputerName( &CompName_U,
  2806. &Hostname_U,
  2807. FALSE );
  2808. if ( NT_SUCCESS( Status ) )
  2809. {
  2810. CompName_A.Buffer = ComputerName ;
  2811. CompName_A.Length = 0 ;
  2812. CompName_A.MaximumLength = (USHORT) *nSize ;
  2813. Status = RtlUnicodeStringToAnsiString( &CompName_A, &CompName_U, FALSE );
  2814. if ( NT_SUCCESS( Status ) )
  2815. {
  2816. *nSize = CompName_A.Length ;
  2817. }
  2818. }
  2819. }
  2820. if ( !NT_SUCCESS( Status ) )
  2821. {
  2822. BaseSetLastNTError( Status );
  2823. return FALSE ;
  2824. }
  2825. return TRUE ;
  2826. }
  2827. #include "dfsfsctl.h"
  2828. DWORD
  2829. BasepGetComputerNameFromNtPath (
  2830. PUNICODE_STRING NtPathName,
  2831. HANDLE hFile,
  2832. LPWSTR lpBuffer,
  2833. LPDWORD nSize
  2834. )
  2835. /*++
  2836. Routine Description:
  2837. Look at a path and determine the computer name of the host machine.
  2838. In the future, we should remove this code, and add the capbility to query
  2839. handles for their computer name.
  2840. The name can only be obtained for NetBios paths - if the path is IP or DNS
  2841. an error is returned. (If the NetBios name has a "." in it, it will
  2842. cause an error because it will be misinterpreted as a DNS path. This case
  2843. becomes less and less likely as the NT5 UI doesn't allow such computer names.)
  2844. For DFS paths, the leaf server's name is returned, as long as it wasn't
  2845. joined to its parent with an IP or DNS path name.
  2846. Arguments:
  2847. NtPathName - points to a unicode string with the path to query.
  2848. lpBuffer - points to buffer receives the computer name
  2849. nSize - points to dword with the size of the input buffer, and the length
  2850. (in characters, not including the null terminator) of the computer name
  2851. on output.
  2852. Return Value:
  2853. A Win32 error code.
  2854. --*/
  2855. {
  2856. ULONG cbComputer = 0;
  2857. DWORD dwError = ERROR_BAD_PATHNAME;
  2858. ULONG AvailableLength = 0;
  2859. PWCHAR PathCharacter = NULL;
  2860. BOOL CheckForDfs = TRUE;
  2861. NTSTATUS NtStatus = STATUS_SUCCESS;
  2862. IO_STATUS_BLOCK IoStatusBlock;
  2863. WCHAR FileNameInfoBuffer[MAX_PATH+sizeof(FILE_NAME_INFORMATION)];
  2864. PFILE_NAME_INFORMATION FileNameInfo = (PFILE_NAME_INFORMATION)FileNameInfoBuffer;
  2865. WCHAR DfsServerPathName[ MAX_PATH + 1 ];
  2866. WCHAR DosDevice[3] = { L"A:" };
  2867. WCHAR DosDeviceMapping[ MAX_PATH + 1 ];
  2868. UNICODE_STRING UnicodeComputerName;
  2869. const UNICODE_STRING NtUncPathNamePrefix = { 16, 18, L"\\??\\UNC\\"};
  2870. const ULONG cchNtUncPathNamePrefix = 8;
  2871. const UNICODE_STRING NtDrivePathNamePrefix = { 8, 10, L"\\??\\" };
  2872. const ULONG cchNtDrivePathNamePrefix = 4;
  2873. RtlInitUnicodeString( &UnicodeComputerName, NULL );
  2874. // Is this a UNC path?
  2875. if( RtlPrefixString( (PSTRING)&NtUncPathNamePrefix, (PSTRING)NtPathName, TRUE )) {
  2876. // Make sure there's some more to this path than just the prefix
  2877. if( NtPathName->Length <= NtUncPathNamePrefix.Length )
  2878. goto Exit;
  2879. // It appears to be a valid UNC path. Point to the beginning of the computer
  2880. // name, and calculate how much room is left in NtPathName after that.
  2881. UnicodeComputerName.Buffer = &NtPathName->Buffer[ NtUncPathNamePrefix.Length/sizeof(WCHAR) ];
  2882. AvailableLength = NtPathName->Length - NtUncPathNamePrefix.Length;
  2883. }
  2884. // If it's not a UNC path, then is it a drive-letter path?
  2885. else if( RtlPrefixString( (PSTRING)&NtDrivePathNamePrefix, (PSTRING)NtPathName, TRUE )
  2886. &&
  2887. NtPathName->Buffer[ cchNtDrivePathNamePrefix + 1 ] == L':' ) {
  2888. // It's a drive letter path, but it could still be local or remote
  2889. static const WCHAR RedirectorMappingPrefix[] = { L"\\Device\\LanmanRedirector\\;" };
  2890. static const WCHAR LocalVolumeMappingPrefix[] = { L"\\Device\\Harddisk" };
  2891. static const WCHAR CDRomMappingPrefix[] = { L"\\Device\\CdRom" };
  2892. static const WCHAR FloppyMappingPrefix[] = { L"\\Device\\Floppy" };
  2893. static const WCHAR DfsMappingPrefix[] = { L"\\Device\\WinDfs\\" };
  2894. // Get the correct, upper-cased, drive letter into DosDevice.
  2895. DosDevice[0] = NtPathName->Buffer[ cchNtDrivePathNamePrefix ];
  2896. if( L'a' <= DosDevice[0] && DosDevice[0] <= L'z' )
  2897. DosDevice[0] = L'A' + (DosDevice[0] - L'a');
  2898. // Map the drive letter to its symbolic link under \??. E.g., say C:, D: & R:
  2899. // are local/DFS/rdr drives, respectively. You would then see something like:
  2900. //
  2901. // C: => \Device\Volume1
  2902. // D: => \Device\WinDfs\G
  2903. // R: => \Device\LanmanRedirector\;R:0\scratch\scratch
  2904. if( !QueryDosDeviceW( DosDevice, DosDeviceMapping, sizeof(DosDeviceMapping)/sizeof(DosDeviceMapping[0]) )) {
  2905. dwError = GetLastError();
  2906. goto Exit;
  2907. }
  2908. // Now that we have the DosDeviceMapping, we can check ... Is this a rdr drive?
  2909. if( // Does it begin with "\Device\LanmanRedirector\;" ?
  2910. DosDeviceMapping == wcsstr( DosDeviceMapping, RedirectorMappingPrefix )
  2911. &&
  2912. // Are the next letters the correct drive letter, a colon, and a whack?
  2913. ( DosDevice[0] == DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) - 1 ]
  2914. &&
  2915. L':' == DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) ]
  2916. &&
  2917. (UnicodeComputerName.Buffer = wcschr(&DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) + 1 ], L'\\'))
  2918. )) {
  2919. // We have a valid rdr drive. Point to the beginning of the computer
  2920. // name, and calculate how much room is availble in DosDeviceMapping after that.
  2921. UnicodeComputerName.Buffer += 1;
  2922. AvailableLength = sizeof(DosDeviceMapping) - sizeof(DosDeviceMapping[0]) * (ULONG)(UnicodeComputerName.Buffer - DosDeviceMapping);
  2923. // We know now that it's not a DFS path
  2924. CheckForDfs = FALSE;
  2925. }
  2926. // If it's not a rdr drive, then maybe it's a local volume, floppy, or cdrom
  2927. else if( DosDeviceMapping == wcsstr( DosDeviceMapping, LocalVolumeMappingPrefix )
  2928. ||
  2929. DosDeviceMapping == wcsstr( DosDeviceMapping, CDRomMappingPrefix )
  2930. ||
  2931. DosDeviceMapping == wcsstr( DosDeviceMapping, FloppyMappingPrefix ) ) {
  2932. // We have a local drive, so just return the local computer name.
  2933. CheckForDfs = FALSE;
  2934. if( !GetComputerNameW( lpBuffer, nSize))
  2935. dwError = GetLastError();
  2936. else
  2937. dwError = ERROR_SUCCESS;
  2938. goto Exit;
  2939. }
  2940. // Finally, check to see if it's a DFS drive
  2941. else if( DosDeviceMapping == wcsstr( DosDeviceMapping, DfsMappingPrefix )) {
  2942. // Get the full UNC name of this DFS path. Later, we'll call the DFS
  2943. // driver to find out what the actual server name is.
  2944. NtStatus = NtQueryInformationFile(
  2945. hFile,
  2946. &IoStatusBlock,
  2947. FileNameInfo,
  2948. sizeof(FileNameInfoBuffer),
  2949. FileNameInformation
  2950. );
  2951. if( !NT_SUCCESS(NtStatus) ) {
  2952. dwError = RtlNtStatusToDosError(NtStatus);
  2953. goto Exit;
  2954. }
  2955. UnicodeComputerName.Buffer = FileNameInfo->FileName + 1;
  2956. AvailableLength = FileNameInfo->FileNameLength;
  2957. }
  2958. // Otherwise, it's not a rdr, dfs, or local drive, so there's nothing we can do.
  2959. else
  2960. goto Exit;
  2961. } // else if( RtlPrefixString( (PSTRING)&NtDrivePathNamePrefix, (PSTRING)NtPathName, TRUE ) ...
  2962. else {
  2963. dwError = ERROR_BAD_PATHNAME;
  2964. goto Exit;
  2965. }
  2966. // If we couldn't determine above if whether or not this is a DFS path, let the
  2967. // DFS driver decide now.
  2968. if( CheckForDfs && INVALID_HANDLE_VALUE != hFile ) {
  2969. HANDLE hDFS = INVALID_HANDLE_VALUE;
  2970. UNICODE_STRING DfsDriverName;
  2971. OBJECT_ATTRIBUTES ObjectAttributes;
  2972. WCHAR *DfsPathName = UnicodeComputerName.Buffer - 1; // Back up to the whack
  2973. ULONG DfsPathNameLength = AvailableLength + sizeof(WCHAR);
  2974. // Open the DFS driver
  2975. RtlInitUnicodeString( &DfsDriverName, DFS_DRIVER_NAME );
  2976. InitializeObjectAttributes( &ObjectAttributes,
  2977. &DfsDriverName,
  2978. OBJ_CASE_INSENSITIVE,
  2979. NULL,
  2980. NULL
  2981. );
  2982. NtStatus = NtCreateFile(
  2983. &hDFS,
  2984. SYNCHRONIZE,
  2985. &ObjectAttributes,
  2986. &IoStatusBlock,
  2987. NULL,
  2988. FILE_ATTRIBUTE_NORMAL,
  2989. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2990. FILE_OPEN_IF,
  2991. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  2992. NULL,
  2993. 0
  2994. );
  2995. if( !NT_SUCCESS(NtStatus) ) {
  2996. dwError = RtlNtStatusToDosError(NtStatus);
  2997. goto Exit;
  2998. }
  2999. // Query DFS's cache for the server name. The name is guaranteed to
  3000. // remain in the cache as long as the file is open.
  3001. if( L'\\' != DfsPathName[0] ) {
  3002. NtClose(hDFS);
  3003. dwError = ERROR_BAD_PATHNAME;
  3004. goto Exit;
  3005. }
  3006. NtStatus = NtFsControlFile(
  3007. hDFS,
  3008. NULL, // Event,
  3009. NULL, // ApcRoutine,
  3010. NULL, // ApcContext,
  3011. &IoStatusBlock,
  3012. FSCTL_DFS_GET_SERVER_NAME,
  3013. DfsPathName,
  3014. DfsPathNameLength,
  3015. DfsServerPathName,
  3016. sizeof(DfsServerPathName)
  3017. );
  3018. NtClose( hDFS );
  3019. // STATUS_OBJECT_NAME_NOT_FOUND means that it's not a DFS path
  3020. if( !NT_SUCCESS(NtStatus) ) {
  3021. if( STATUS_OBJECT_NAME_NOT_FOUND != NtStatus ) {
  3022. dwError = RtlNtStatusToDosError(NtStatus);
  3023. goto Exit;
  3024. }
  3025. }
  3026. else if( L'\0' != DfsServerPathName[0] ) {
  3027. // The previous DFS call returns the server-specific path to the file in UNC form.
  3028. // Point UnicodeComputerName to just past the two whacks.
  3029. AvailableLength = wcslen(DfsServerPathName) * sizeof(WCHAR);
  3030. if( 3*sizeof(WCHAR) > AvailableLength
  3031. ||
  3032. L'\\' != DfsServerPathName[0]
  3033. ||
  3034. L'\\' != DfsServerPathName[1] )
  3035. {
  3036. dwError = ERROR_BAD_PATHNAME;
  3037. goto Exit;
  3038. }
  3039. UnicodeComputerName.Buffer = DfsServerPathName + 2;
  3040. AvailableLength -= 2 * sizeof(WCHAR);
  3041. }
  3042. }
  3043. // If we get here, then the computer name\share is pointed to by UnicodeComputerName.Buffer.
  3044. // But the Length is currently zero, so we search for the whack that separates
  3045. // the computer name from the share, and set the Length to include just the computer name.
  3046. PathCharacter = UnicodeComputerName.Buffer;
  3047. while( ( (ULONG) ((PCHAR)PathCharacter - (PCHAR)UnicodeComputerName.Buffer) < AvailableLength)
  3048. &&
  3049. *PathCharacter != L'\\' ) {
  3050. // If we found a '.', we fail because this is probably a DNS or IP name.
  3051. if( L'.' == *PathCharacter ) {
  3052. dwError = ERROR_BAD_PATHNAME;
  3053. goto Exit;
  3054. }
  3055. PathCharacter++;
  3056. }
  3057. // Set the computer name length
  3058. UnicodeComputerName.Length = UnicodeComputerName.MaximumLength
  3059. = (USHORT) ((PCHAR)PathCharacter - (PCHAR)UnicodeComputerName.Buffer);
  3060. // Fail if the computer name exceeded the length of the input NtPathName,
  3061. // or if the length exceeds that allowed.
  3062. if( UnicodeComputerName.Length >= AvailableLength
  3063. ||
  3064. UnicodeComputerName.Length > MAX_COMPUTERNAME_LENGTH*sizeof(WCHAR) ) {
  3065. goto Exit;
  3066. }
  3067. // Copy the computer name into the caller's buffer, as long as there's enough
  3068. // room for the name & a terminating '\0'.
  3069. if( UnicodeComputerName.Length + sizeof(WCHAR) > *nSize * sizeof(WCHAR) ) {
  3070. dwError = ERROR_BUFFER_OVERFLOW;
  3071. goto Exit;
  3072. }
  3073. RtlCopyMemory( lpBuffer, UnicodeComputerName.Buffer, UnicodeComputerName.Length );
  3074. *nSize = UnicodeComputerName.Length / sizeof(WCHAR);
  3075. lpBuffer[ *nSize ] = L'\0';
  3076. dwError = ERROR_SUCCESS;
  3077. Exit:
  3078. return( dwError );
  3079. }