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.

795 lines
18 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. reg.c
  5. Abstract:
  6. This module provides helpers to call the registry used by both
  7. the client and server sides of the workstation.
  8. Author:
  9. Rita Wong (ritaw) 22-Apr-1993
  10. --*/
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windef.h>
  17. #include <winerror.h>
  18. #include <winbase.h>
  19. #include <winreg.h>
  20. #include <winsvc.h>
  21. #include <nwsnames.h>
  22. #include <nwreg.h>
  23. #include <nwapi.h>
  24. #include <lmcons.h>
  25. #include <lmerr.h>
  26. #define LMSERVER_LINKAGE_REGKEY L"System\\CurrentControlSet\\Services\\LanmanServer\\Linkage"
  27. #define OTHERDEPS_VALUENAME L"OtherDependencies"
  28. #define LANMAN_SERVER L"LanmanServer"
  29. //
  30. // Forward Declare
  31. //
  32. static
  33. DWORD
  34. NwRegQueryValueExW(
  35. IN HKEY hKey,
  36. IN LPWSTR lpValueName,
  37. OUT LPDWORD lpReserved,
  38. OUT LPDWORD lpType,
  39. OUT LPBYTE lpData,
  40. IN OUT LPDWORD lpcbData
  41. );
  42. DWORD
  43. CalcNullNullSize(
  44. WCHAR *pszNullNull
  45. ) ;
  46. WCHAR *
  47. FindStringInNullNull(
  48. WCHAR *pszNullNull,
  49. WCHAR *pszString
  50. ) ;
  51. VOID
  52. RemoveNWCFromNullNullList(
  53. WCHAR *OtherDeps
  54. ) ;
  55. DWORD RemoveNwcDependency(
  56. VOID
  57. ) ;
  58. DWORD
  59. NwReadRegValue(
  60. IN HKEY Key,
  61. IN LPWSTR ValueName,
  62. OUT LPWSTR *Value
  63. )
  64. /*++
  65. Routine Description:
  66. This function allocates the output buffer and reads the requested
  67. value from the registry into it.
  68. Arguments:
  69. Key - Supplies opened handle to the key to read from.
  70. ValueName - Supplies name of the value to retrieve data.
  71. Value - Returns a pointer to the output buffer which points to
  72. the memory allocated and contains the data read in from the
  73. registry. This pointer must be freed with LocalFree when done.
  74. Return Value:
  75. ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
  76. Error from registry call.
  77. --*/
  78. {
  79. LONG RegError;
  80. DWORD NumRequired = 0;
  81. DWORD ValueType;
  82. //
  83. // Set returned buffer pointer to NULL.
  84. //
  85. *Value = NULL;
  86. RegError = NwRegQueryValueExW(
  87. Key,
  88. ValueName,
  89. NULL,
  90. &ValueType,
  91. (LPBYTE) NULL,
  92. &NumRequired
  93. );
  94. if (RegError != ERROR_SUCCESS && NumRequired > 0) {
  95. if ((*Value = (LPWSTR) LocalAlloc(
  96. LMEM_ZEROINIT,
  97. (UINT) NumRequired
  98. )) == NULL) {
  99. KdPrint(("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n",
  100. NumRequired, GetLastError()));
  101. return ERROR_NOT_ENOUGH_MEMORY;
  102. }
  103. RegError = NwRegQueryValueExW(
  104. Key,
  105. ValueName,
  106. NULL,
  107. &ValueType,
  108. (LPBYTE) *Value,
  109. &NumRequired
  110. );
  111. }
  112. else if (RegError == ERROR_SUCCESS) {
  113. KdPrint(("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer."));
  114. return ERROR_FILE_NOT_FOUND;
  115. }
  116. if (RegError != ERROR_SUCCESS) {
  117. if (*Value != NULL) {
  118. (void) LocalFree((HLOCAL) *Value);
  119. *Value = NULL;
  120. }
  121. return (DWORD) RegError;
  122. }
  123. return NO_ERROR;
  124. }
  125. static
  126. DWORD
  127. NwRegQueryValueExW(
  128. IN HKEY hKey,
  129. IN LPWSTR lpValueName,
  130. OUT LPDWORD lpReserved,
  131. OUT LPDWORD lpType,
  132. OUT LPBYTE lpData,
  133. IN OUT LPDWORD lpcbData
  134. )
  135. /*++
  136. Routine Description:
  137. This routine supports the same functionality as Win32 RegQueryValueEx
  138. API, except that it works. It returns the correct lpcbData value when
  139. a NULL output buffer is specified.
  140. This code is stolen from the service controller.
  141. Arguments:
  142. same as RegQueryValueEx
  143. Return Value:
  144. NO_ERROR or reason for failure.
  145. --*/
  146. {
  147. NTSTATUS ntstatus;
  148. UNICODE_STRING ValueName;
  149. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  150. DWORD BufSize;
  151. UNREFERENCED_PARAMETER(lpReserved);
  152. //
  153. // Make sure we have a buffer size if the buffer is present.
  154. //
  155. if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) {
  156. return ERROR_INVALID_PARAMETER;
  157. }
  158. RtlInitUnicodeString(&ValueName, lpValueName);
  159. //
  160. // Allocate memory for the ValueKeyInfo
  161. //
  162. BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) +
  163. ValueName.Length
  164. - sizeof(WCHAR); // subtract memory for 1 char because it's included
  165. // in the sizeof(KEY_VALUE_FULL_INFORMATION).
  166. KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc(
  167. LMEM_ZEROINIT,
  168. (UINT) BufSize
  169. );
  170. if (KeyValueInfo == NULL) {
  171. KdPrint(("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n",
  172. GetLastError()));
  173. return ERROR_NOT_ENOUGH_MEMORY;
  174. }
  175. ntstatus = NtQueryValueKey(
  176. hKey,
  177. &ValueName,
  178. KeyValueFullInformation,
  179. (PVOID) KeyValueInfo,
  180. (ULONG) BufSize,
  181. (PULONG) &BufSize
  182. );
  183. if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW))
  184. && ARGUMENT_PRESENT(lpcbData)) {
  185. *lpcbData = KeyValueInfo->DataLength;
  186. }
  187. if (NT_SUCCESS(ntstatus)) {
  188. if (ARGUMENT_PRESENT(lpType)) {
  189. *lpType = KeyValueInfo->Type;
  190. }
  191. if (ARGUMENT_PRESENT(lpData)) {
  192. memcpy(
  193. lpData,
  194. (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
  195. KeyValueInfo->DataLength
  196. );
  197. }
  198. }
  199. (void) LocalFree((HLOCAL) KeyValueInfo);
  200. return RtlNtStatusToDosError(ntstatus);
  201. }
  202. VOID
  203. NwLuidToWStr(
  204. IN PLUID LogonId,
  205. OUT LPWSTR LogonIdStr
  206. )
  207. /*++
  208. Routine Description:
  209. This routine converts a LUID into a string in hex value format so
  210. that it can be used as a registry key.
  211. Arguments:
  212. LogonId - Supplies the LUID.
  213. LogonIdStr - Receives the string. This routine assumes that this
  214. buffer is large enough to fit 17 characters.
  215. Return Value:
  216. None.
  217. --*/
  218. {
  219. swprintf(LogonIdStr, L"%08lx%08lx", LogonId->HighPart, LogonId->LowPart);
  220. }
  221. VOID
  222. NwWStrToLuid(
  223. IN LPWSTR LogonIdStr,
  224. OUT PLUID LogonId
  225. )
  226. /*++
  227. Routine Description:
  228. This routine converts a string in hex value format into a LUID.
  229. Arguments:
  230. LogonIdStr - Supplies the string.
  231. LogonId - Receives the LUID.
  232. Return Value:
  233. None.
  234. --*/
  235. {
  236. swscanf(LogonIdStr, L"%08lx%08lx", &LogonId->HighPart, &LogonId->LowPart);
  237. }
  238. DWORD
  239. NwDeleteInteractiveLogon(
  240. IN PLUID Id OPTIONAL
  241. )
  242. /*++
  243. Routine Description:
  244. This routine deletes a specific interactive logon ID key in the registry
  245. if a logon ID is specified, otherwise it deletes all interactive logon
  246. ID keys.
  247. Arguments:
  248. Id - Supplies the logon ID to delete. NULL means delete all.
  249. Return Status:
  250. None.
  251. --*/
  252. {
  253. LONG RegError;
  254. LONG DelError = ERROR_SUCCESS;
  255. HKEY InteractiveLogonKey;
  256. WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
  257. RegError = RegOpenKeyExW(
  258. HKEY_LOCAL_MACHINE,
  259. NW_INTERACTIVE_LOGON_REGKEY,
  260. REG_OPTION_NON_VOLATILE,
  261. KEY_READ | KEY_WRITE | DELETE,
  262. &InteractiveLogonKey
  263. );
  264. if (RegError != ERROR_SUCCESS) {
  265. return RegError;
  266. }
  267. if (ARGUMENT_PRESENT(Id)) {
  268. //
  269. // Delete the key specified.
  270. //
  271. NwLuidToWStr(Id, LogonIdKey);
  272. DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
  273. if ( DelError )
  274. KdPrint((" NwDeleteInteractiveLogon: failed to delete logon %lu\n", DelError));
  275. }
  276. else {
  277. //
  278. // Delete all interactive logon ID keys.
  279. //
  280. do {
  281. RegError = RegEnumKeyW(
  282. InteractiveLogonKey,
  283. 0,
  284. LogonIdKey,
  285. sizeof(LogonIdKey) / sizeof(WCHAR)
  286. );
  287. if (RegError == ERROR_SUCCESS) {
  288. //
  289. // Got a logon id key, delete it.
  290. //
  291. DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
  292. }
  293. else if (RegError != ERROR_NO_MORE_ITEMS) {
  294. KdPrint((" NwDeleteInteractiveLogon: failed to enum logon IDs %lu\n", RegError));
  295. }
  296. } while (RegError == ERROR_SUCCESS);
  297. }
  298. (void) RegCloseKey(InteractiveLogonKey);
  299. return ((DWORD) DelError);
  300. }
  301. VOID
  302. NwDeleteCurrentUser(
  303. VOID
  304. )
  305. /*++
  306. Routine Description:
  307. This routine deletes the current user value under the parameters key.
  308. Arguments:
  309. None.
  310. Return Value:
  311. None.
  312. --*/
  313. {
  314. LONG RegError;
  315. HKEY WkstaKey;
  316. //
  317. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  318. // \NWCWorkstation\Parameters
  319. //
  320. RegError = RegOpenKeyExW(
  321. HKEY_LOCAL_MACHINE,
  322. NW_WORKSTATION_REGKEY,
  323. REG_OPTION_NON_VOLATILE,
  324. KEY_READ | KEY_WRITE | DELETE,
  325. &WkstaKey
  326. );
  327. if (RegError != NO_ERROR) {
  328. KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters key unexpected error %lu!\n",
  329. RegError));
  330. return;
  331. }
  332. //
  333. // Delete CurrentUser value first so that the workstation won't be
  334. // reading this stale value. Ignore error since it may not exist.
  335. //
  336. (void) RegDeleteValueW(
  337. WkstaKey,
  338. NW_CURRENTUSER_VALUENAME
  339. );
  340. (void) RegCloseKey(WkstaKey);
  341. }
  342. DWORD
  343. NwDeleteServiceLogon(
  344. IN PLUID Id OPTIONAL
  345. )
  346. /*++
  347. Routine Description:
  348. This routine deletes a specific service logon ID key in the registry
  349. if a logon ID is specified, otherwise it deletes all service logon
  350. ID keys.
  351. Arguments:
  352. Id - Supplies the logon ID to delete. NULL means delete all.
  353. Return Status:
  354. None.
  355. --*/
  356. {
  357. LONG RegError;
  358. LONG DelError = STATUS_SUCCESS;
  359. HKEY ServiceLogonKey;
  360. WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
  361. RegError = RegOpenKeyExW(
  362. HKEY_LOCAL_MACHINE,
  363. NW_SERVICE_LOGON_REGKEY,
  364. REG_OPTION_NON_VOLATILE,
  365. KEY_READ | KEY_WRITE | DELETE,
  366. &ServiceLogonKey
  367. );
  368. if (RegError != ERROR_SUCCESS) {
  369. return RegError;
  370. }
  371. if (ARGUMENT_PRESENT(Id)) {
  372. //
  373. // Delete the key specified.
  374. //
  375. NwLuidToWStr(Id, LogonIdKey);
  376. DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
  377. }
  378. else {
  379. //
  380. // Delete all service logon ID keys.
  381. //
  382. do {
  383. RegError = RegEnumKeyW(
  384. ServiceLogonKey,
  385. 0,
  386. LogonIdKey,
  387. sizeof(LogonIdKey) / sizeof(WCHAR)
  388. );
  389. if (RegError == ERROR_SUCCESS) {
  390. //
  391. // Got a logon id key, delete it.
  392. //
  393. DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
  394. }
  395. else if (RegError != ERROR_NO_MORE_ITEMS) {
  396. KdPrint((" NwDeleteServiceLogon: failed to enum logon IDs %lu\n", RegError));
  397. }
  398. } while (RegError == ERROR_SUCCESS);
  399. }
  400. (void) RegCloseKey(ServiceLogonKey);
  401. return ((DWORD) DelError);
  402. }
  403. DWORD
  404. CalcNullNullSize(
  405. WCHAR *pszNullNull
  406. )
  407. /*++
  408. Routine Description:
  409. Walk thru a NULL NULL string, counting the number of
  410. characters, including the 2 nulls at the end.
  411. Arguments:
  412. Pointer to a NULL NULL string
  413. Return Status:
  414. Count of number of *characters*. See description.
  415. --*/
  416. {
  417. DWORD dwSize = 0 ;
  418. WCHAR *pszTmp = pszNullNull ;
  419. if (!pszNullNull)
  420. return 0 ;
  421. while (*pszTmp)
  422. {
  423. DWORD dwLen = wcslen(pszTmp) + 1 ;
  424. dwSize += dwLen ;
  425. pszTmp += dwLen ;
  426. }
  427. return (dwSize+1) ;
  428. }
  429. WCHAR *
  430. FindStringInNullNull(
  431. WCHAR *pszNullNull,
  432. WCHAR *pszString
  433. )
  434. /*++
  435. Routine Description:
  436. Walk thru a NULL NULL string, looking for the search string
  437. Arguments:
  438. pszNullNull: the string list we will search.
  439. pszString: what we are searching for.
  440. Return Status:
  441. The start of the string if found. Null, otherwise.
  442. --*/
  443. {
  444. WCHAR *pszTmp = pszNullNull ;
  445. if (!pszNullNull || !*pszNullNull)
  446. return NULL ;
  447. do {
  448. if (_wcsicmp(pszTmp,pszString)==0)
  449. return pszTmp ;
  450. pszTmp += wcslen(pszTmp) + 1 ;
  451. } while (*pszTmp) ;
  452. return NULL ;
  453. }
  454. VOID
  455. RemoveNWCFromNullNullList(
  456. WCHAR *OtherDeps
  457. )
  458. /*++
  459. Routine Description:
  460. Remove the NWCWorkstation string from a null null string.
  461. Arguments:
  462. OtherDeps: the string list we will munge.
  463. Return Status:
  464. None.
  465. --*/
  466. {
  467. LPWSTR pszTmp0, pszTmp1 ;
  468. //
  469. // find the NWCWorkstation string
  470. //
  471. pszTmp0 = FindStringInNullNull(OtherDeps, NW_WORKSTATION_SERVICE) ;
  472. if (!pszTmp0)
  473. return ;
  474. pszTmp1 = pszTmp0 + wcslen(pszTmp0) + 1 ; // skip past it
  475. //
  476. // shift the rest up
  477. //
  478. memmove(pszTmp0, pszTmp1, CalcNullNullSize(pszTmp1)*sizeof(WCHAR)) ;
  479. }
  480. DWORD RemoveNwcDependency(
  481. VOID
  482. )
  483. {
  484. SC_HANDLE ScManager = NULL;
  485. SC_HANDLE Service = NULL;
  486. LPQUERY_SERVICE_CONFIGW lpServiceConfig = NULL;
  487. DWORD err = NO_ERROR, dwBufferSize = 4096, dwBytesNeeded = 0;
  488. LPWSTR Deps = NULL ;
  489. lpServiceConfig = (LPQUERY_SERVICE_CONFIGW) LocalAlloc(LPTR, dwBufferSize) ;
  490. if (lpServiceConfig == NULL) {
  491. err = GetLastError();
  492. goto ExitPoint ;
  493. }
  494. ScManager = OpenSCManagerW(
  495. NULL,
  496. NULL,
  497. SC_MANAGER_CONNECT
  498. );
  499. if (ScManager == NULL) {
  500. err = GetLastError();
  501. goto ExitPoint ;
  502. }
  503. Service = OpenServiceW(
  504. ScManager,
  505. LANMAN_SERVER,
  506. (SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG)
  507. );
  508. if (Service == NULL) {
  509. err = GetLastError();
  510. goto ExitPoint ;
  511. }
  512. if (!QueryServiceConfigW(
  513. Service,
  514. lpServiceConfig, // address of service config. structure
  515. dwBufferSize, // size of service configuration buffer
  516. &dwBytesNeeded // address of variable for bytes needed
  517. )) {
  518. err = GetLastError();
  519. if (err == ERROR_INSUFFICIENT_BUFFER) {
  520. err = NO_ERROR ;
  521. dwBufferSize = dwBytesNeeded ;
  522. lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)
  523. LocalAlloc(LPTR, dwBufferSize) ;
  524. if (lpServiceConfig == NULL) {
  525. err = GetLastError();
  526. goto ExitPoint ;
  527. }
  528. if (!QueryServiceConfigW(
  529. Service,
  530. lpServiceConfig, // address of service config. structure
  531. dwBufferSize, // size of service configuration buffer
  532. &dwBytesNeeded // address of variable for bytes needed
  533. )) {
  534. err = GetLastError();
  535. }
  536. }
  537. if (err != NO_ERROR) {
  538. goto ExitPoint ;
  539. }
  540. }
  541. Deps = lpServiceConfig->lpDependencies ;
  542. RemoveNWCFromNullNullList(Deps) ;
  543. if (!ChangeServiceConfigW(
  544. Service,
  545. SERVICE_NO_CHANGE, // service type (no change)
  546. SERVICE_NO_CHANGE, // start type (no change)
  547. SERVICE_NO_CHANGE, // error control (no change)
  548. NULL, // binary path name (NULL for no change)
  549. NULL, // load order group (NULL for no change)
  550. NULL, // tag id (NULL for no change)
  551. Deps,
  552. NULL, // service start name (NULL for no change)
  553. NULL, // password (NULL for no change)
  554. NULL // display name (NULL for no change)
  555. )) {
  556. err = GetLastError();
  557. goto ExitPoint ;
  558. }
  559. ExitPoint:
  560. if (ScManager) {
  561. CloseServiceHandle(ScManager);
  562. }
  563. if (Service) {
  564. CloseServiceHandle(Service);
  565. }
  566. if (lpServiceConfig) {
  567. (void) LocalFree(lpServiceConfig) ;
  568. }
  569. return err ;
  570. }