Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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