Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1231 lines
27 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. static
  43. DWORD
  44. EnumAndDeleteShares(
  45. VOID
  46. ) ;
  47. DWORD
  48. CalcNullNullSize(
  49. WCHAR *pszNullNull
  50. ) ;
  51. WCHAR *
  52. FindStringInNullNull(
  53. WCHAR *pszNullNull,
  54. WCHAR *pszString
  55. ) ;
  56. VOID
  57. RemoveNWCFromNullNullList(
  58. WCHAR *OtherDeps
  59. ) ;
  60. DWORD RemoveNwcDependency(
  61. VOID
  62. ) ;
  63. DWORD
  64. NwReadRegValue(
  65. IN HKEY Key,
  66. IN LPWSTR ValueName,
  67. OUT LPWSTR *Value
  68. )
  69. /*++
  70. Routine Description:
  71. This function allocates the output buffer and reads the requested
  72. value from the registry into it.
  73. Arguments:
  74. Key - Supplies opened handle to the key to read from.
  75. ValueName - Supplies name of the value to retrieve data.
  76. Value - Returns a pointer to the output buffer which points to
  77. the memory allocated and contains the data read in from the
  78. registry. This pointer must be freed with LocalFree when done.
  79. Return Value:
  80. ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
  81. Error from registry call.
  82. --*/
  83. {
  84. LONG RegError;
  85. DWORD NumRequired = 0;
  86. DWORD ValueType;
  87. //
  88. // Set returned buffer pointer to NULL.
  89. //
  90. *Value = NULL;
  91. RegError = NwRegQueryValueExW(
  92. Key,
  93. ValueName,
  94. NULL,
  95. &ValueType,
  96. (LPBYTE) NULL,
  97. &NumRequired
  98. );
  99. if (RegError != ERROR_SUCCESS && NumRequired > 0) {
  100. if ((*Value = (LPWSTR) LocalAlloc(
  101. LMEM_ZEROINIT,
  102. (UINT) NumRequired
  103. )) == NULL) {
  104. KdPrint(("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n",
  105. NumRequired, GetLastError()));
  106. return ERROR_NOT_ENOUGH_MEMORY;
  107. }
  108. RegError = NwRegQueryValueExW(
  109. Key,
  110. ValueName,
  111. NULL,
  112. &ValueType,
  113. (LPBYTE) *Value,
  114. &NumRequired
  115. );
  116. }
  117. else if (RegError == ERROR_SUCCESS) {
  118. KdPrint(("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer."));
  119. return ERROR_FILE_NOT_FOUND;
  120. }
  121. if (RegError != ERROR_SUCCESS) {
  122. if (*Value != NULL) {
  123. (void) LocalFree((HLOCAL) *Value);
  124. *Value = NULL;
  125. }
  126. return (DWORD) RegError;
  127. }
  128. return NO_ERROR;
  129. }
  130. static
  131. DWORD
  132. NwRegQueryValueExW(
  133. IN HKEY hKey,
  134. IN LPWSTR lpValueName,
  135. OUT LPDWORD lpReserved,
  136. OUT LPDWORD lpType,
  137. OUT LPBYTE lpData,
  138. IN OUT LPDWORD lpcbData
  139. )
  140. /*++
  141. Routine Description:
  142. This routine supports the same functionality as Win32 RegQueryValueEx
  143. API, except that it works. It returns the correct lpcbData value when
  144. a NULL output buffer is specified.
  145. This code is stolen from the service controller.
  146. Arguments:
  147. same as RegQueryValueEx
  148. Return Value:
  149. NO_ERROR or reason for failure.
  150. --*/
  151. {
  152. NTSTATUS ntstatus;
  153. UNICODE_STRING ValueName;
  154. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  155. DWORD BufSize;
  156. UNREFERENCED_PARAMETER(lpReserved);
  157. //
  158. // Make sure we have a buffer size if the buffer is present.
  159. //
  160. if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) {
  161. return ERROR_INVALID_PARAMETER;
  162. }
  163. RtlInitUnicodeString(&ValueName, lpValueName);
  164. //
  165. // Allocate memory for the ValueKeyInfo
  166. //
  167. BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) +
  168. ValueName.Length
  169. - sizeof(WCHAR); // subtract memory for 1 char because it's included
  170. // in the sizeof(KEY_VALUE_FULL_INFORMATION).
  171. KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc(
  172. LMEM_ZEROINIT,
  173. (UINT) BufSize
  174. );
  175. if (KeyValueInfo == NULL) {
  176. KdPrint(("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n",
  177. GetLastError()));
  178. return ERROR_NOT_ENOUGH_MEMORY;
  179. }
  180. ntstatus = NtQueryValueKey(
  181. hKey,
  182. &ValueName,
  183. KeyValueFullInformation,
  184. (PVOID) KeyValueInfo,
  185. (ULONG) BufSize,
  186. (PULONG) &BufSize
  187. );
  188. if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW))
  189. && ARGUMENT_PRESENT(lpcbData)) {
  190. *lpcbData = KeyValueInfo->DataLength;
  191. }
  192. if (NT_SUCCESS(ntstatus)) {
  193. if (ARGUMENT_PRESENT(lpType)) {
  194. *lpType = KeyValueInfo->Type;
  195. }
  196. if (ARGUMENT_PRESENT(lpData)) {
  197. memcpy(
  198. lpData,
  199. (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
  200. KeyValueInfo->DataLength
  201. );
  202. }
  203. }
  204. (void) LocalFree((HLOCAL) KeyValueInfo);
  205. return RtlNtStatusToDosError(ntstatus);
  206. }
  207. VOID
  208. NwLuidToWStr(
  209. IN PLUID LogonId,
  210. OUT LPWSTR LogonIdStr
  211. )
  212. /*++
  213. Routine Description:
  214. This routine converts a LUID into a string in hex value format so
  215. that it can be used as a registry key.
  216. Arguments:
  217. LogonId - Supplies the LUID.
  218. LogonIdStr - Receives the string. This routine assumes that this
  219. buffer is large enough to fit 17 characters.
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. swprintf(LogonIdStr, L"%08lx%08lx", LogonId->HighPart, LogonId->LowPart);
  225. }
  226. VOID
  227. NwWStrToLuid(
  228. IN LPWSTR LogonIdStr,
  229. OUT PLUID LogonId
  230. )
  231. /*++
  232. Routine Description:
  233. This routine converts a string in hex value format into a LUID.
  234. Arguments:
  235. LogonIdStr - Supplies the string.
  236. LogonId - Receives the LUID.
  237. Return Value:
  238. None.
  239. --*/
  240. {
  241. swscanf(LogonIdStr, L"%08lx%08lx", &LogonId->HighPart, &LogonId->LowPart);
  242. }
  243. DWORD
  244. NwDeleteInteractiveLogon(
  245. IN PLUID Id OPTIONAL
  246. )
  247. /*++
  248. Routine Description:
  249. This routine deletes a specific interactive logon ID key in the registry
  250. if a logon ID is specified, otherwise it deletes all interactive logon
  251. ID keys.
  252. Arguments:
  253. Id - Supplies the logon ID to delete. NULL means delete all.
  254. Return Status:
  255. None.
  256. --*/
  257. {
  258. LONG RegError;
  259. LONG DelError = ERROR_SUCCESS;
  260. HKEY InteractiveLogonKey;
  261. WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
  262. RegError = RegOpenKeyExW(
  263. HKEY_LOCAL_MACHINE,
  264. NW_INTERACTIVE_LOGON_REGKEY,
  265. REG_OPTION_NON_VOLATILE,
  266. KEY_READ | KEY_WRITE | DELETE,
  267. &InteractiveLogonKey
  268. );
  269. if (RegError != ERROR_SUCCESS) {
  270. return RegError;
  271. }
  272. if (ARGUMENT_PRESENT(Id)) {
  273. //
  274. // Delete the key specified.
  275. //
  276. NwLuidToWStr(Id, LogonIdKey);
  277. DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
  278. if ( DelError )
  279. KdPrint((" NwDeleteInteractiveLogon: failed to delete logon %lu\n", DelError));
  280. }
  281. else {
  282. //
  283. // Delete all interactive logon ID keys.
  284. //
  285. do {
  286. RegError = RegEnumKeyW(
  287. InteractiveLogonKey,
  288. 0,
  289. LogonIdKey,
  290. sizeof(LogonIdKey) / sizeof(WCHAR)
  291. );
  292. if (RegError == ERROR_SUCCESS) {
  293. //
  294. // Got a logon id key, delete it.
  295. //
  296. DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
  297. }
  298. else if (RegError != ERROR_NO_MORE_ITEMS) {
  299. KdPrint((" NwDeleteInteractiveLogon: failed to enum logon IDs %lu\n", RegError));
  300. }
  301. } while (RegError == ERROR_SUCCESS);
  302. }
  303. (void) RegCloseKey(InteractiveLogonKey);
  304. return ((DWORD) DelError);
  305. }
  306. VOID
  307. NwDeleteCurrentUser(
  308. VOID
  309. )
  310. /*++
  311. Routine Description:
  312. This routine deletes the current user value under the parameters key.
  313. Arguments:
  314. None.
  315. Return Value:
  316. None.
  317. --*/
  318. {
  319. LONG RegError;
  320. HKEY WkstaKey;
  321. //
  322. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  323. // \NWCWorkstation\Parameters
  324. //
  325. RegError = RegOpenKeyExW(
  326. HKEY_LOCAL_MACHINE,
  327. NW_WORKSTATION_REGKEY,
  328. REG_OPTION_NON_VOLATILE,
  329. KEY_READ | KEY_WRITE | DELETE,
  330. &WkstaKey
  331. );
  332. if (RegError != NO_ERROR) {
  333. KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters key unexpected error %lu!\n",
  334. RegError));
  335. return;
  336. }
  337. //
  338. // Delete CurrentUser value first so that the workstation won't be
  339. // reading this stale value. Ignore error since it may not exist.
  340. //
  341. (void) RegDeleteValueW(
  342. WkstaKey,
  343. NW_CURRENTUSER_VALUENAME
  344. );
  345. (void) RegCloseKey(WkstaKey);
  346. }
  347. DWORD
  348. NwDeleteServiceLogon(
  349. IN PLUID Id OPTIONAL
  350. )
  351. /*++
  352. Routine Description:
  353. This routine deletes a specific service logon ID key in the registry
  354. if a logon ID is specified, otherwise it deletes all service logon
  355. ID keys.
  356. Arguments:
  357. Id - Supplies the logon ID to delete. NULL means delete all.
  358. Return Status:
  359. None.
  360. --*/
  361. {
  362. LONG RegError;
  363. LONG DelError = STATUS_SUCCESS;
  364. HKEY ServiceLogonKey;
  365. WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
  366. RegError = RegOpenKeyExW(
  367. HKEY_LOCAL_MACHINE,
  368. NW_SERVICE_LOGON_REGKEY,
  369. REG_OPTION_NON_VOLATILE,
  370. KEY_READ | KEY_WRITE | DELETE,
  371. &ServiceLogonKey
  372. );
  373. if (RegError != ERROR_SUCCESS) {
  374. return RegError;
  375. }
  376. if (ARGUMENT_PRESENT(Id)) {
  377. //
  378. // Delete the key specified.
  379. //
  380. NwLuidToWStr(Id, LogonIdKey);
  381. DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
  382. }
  383. else {
  384. //
  385. // Delete all service logon ID keys.
  386. //
  387. do {
  388. RegError = RegEnumKeyW(
  389. ServiceLogonKey,
  390. 0,
  391. LogonIdKey,
  392. sizeof(LogonIdKey) / sizeof(WCHAR)
  393. );
  394. if (RegError == ERROR_SUCCESS) {
  395. //
  396. // Got a logon id key, delete it.
  397. //
  398. DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
  399. }
  400. else if (RegError != ERROR_NO_MORE_ITEMS) {
  401. KdPrint((" NwDeleteServiceLogon: failed to enum logon IDs %lu\n", RegError));
  402. }
  403. } while (RegError == ERROR_SUCCESS);
  404. }
  405. (void) RegCloseKey(ServiceLogonKey);
  406. return ((DWORD) DelError);
  407. }
  408. DWORD
  409. NwpRegisterGatewayShare(
  410. IN LPWSTR ShareName,
  411. IN LPWSTR DriveName
  412. )
  413. /*++
  414. Routine Description:
  415. This routine remembers that a gateway share has been created so
  416. that it can be cleanup up when NWCS is uninstalled.
  417. Arguments:
  418. ShareName - name of share
  419. DriveName - name of drive that is shared
  420. Return Status:
  421. Win32 error of any failure.
  422. --*/
  423. {
  424. DWORD status ;
  425. //
  426. // make sure we have valid parameters
  427. //
  428. if (ShareName && DriveName)
  429. {
  430. HKEY hKey ;
  431. DWORD dwDisposition ;
  432. //
  433. //
  434. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  435. // \NWCWorkstation\Shares (create it if not there)
  436. //
  437. status = RegCreateKeyExW(
  438. HKEY_LOCAL_MACHINE,
  439. NW_WORKSTATION_GATEWAY_SHARES,
  440. 0,
  441. L"",
  442. REG_OPTION_NON_VOLATILE,
  443. KEY_WRITE, // desired access
  444. NULL, // default security
  445. &hKey,
  446. &dwDisposition // ignored
  447. );
  448. if ( status )
  449. return status ;
  450. //
  451. // wtite out value with valuename=sharename, valuedata=drive
  452. //
  453. status = RegSetValueExW(
  454. hKey,
  455. ShareName,
  456. 0,
  457. REG_SZ,
  458. (LPBYTE) DriveName,
  459. (wcslen(DriveName)+1) * sizeof(WCHAR)) ;
  460. (void) RegCloseKey( hKey );
  461. }
  462. else
  463. status = ERROR_INVALID_PARAMETER ;
  464. return status ;
  465. }
  466. DWORD
  467. NwpCleanupGatewayShares(
  468. VOID
  469. )
  470. /*++
  471. Routine Description:
  472. This routine cleans up all persistent share info and also tidies
  473. up the registry for NWCS. Later is not needed in uninstall, but is
  474. there so we have a single routine that completely disables the
  475. gateway.
  476. Arguments:
  477. None.
  478. Return Status:
  479. Win32 error for failed APIs.
  480. --*/
  481. {
  482. DWORD status, FinalStatus = NO_ERROR ;
  483. HKEY WkstaKey = NULL,
  484. ServerLinkageKey = NULL ;
  485. LPWSTR OtherDeps = NULL ;
  486. //
  487. // Enumeratre and delete all shares
  488. //
  489. FinalStatus = status = EnumAndDeleteShares() ;
  490. //
  491. // if update registry by cleaning out both Drive and Shares keys.
  492. // ignore return values here. the keys may not be present.
  493. //
  494. (void) RegDeleteKeyW(
  495. HKEY_LOCAL_MACHINE,
  496. NW_WORKSTATION_GATEWAY_DRIVES
  497. ) ;
  498. (void) RegDeleteKeyW(
  499. HKEY_LOCAL_MACHINE,
  500. NW_WORKSTATION_GATEWAY_SHARES
  501. ) ;
  502. //
  503. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  504. // \NWCWorkstation\Parameters
  505. //
  506. status = RegOpenKeyExW(
  507. HKEY_LOCAL_MACHINE,
  508. NW_WORKSTATION_REGKEY,
  509. REG_OPTION_NON_VOLATILE, // options
  510. KEY_WRITE, // desired access
  511. &WkstaKey
  512. );
  513. if (status == ERROR_SUCCESS)
  514. {
  515. //
  516. // delete the gateway account and gateway enabled flag.
  517. // ignore failures here (the values may not be present)
  518. //
  519. (void) RegDeleteValueW(
  520. WkstaKey,
  521. NW_GATEWAYACCOUNT_VALUENAME
  522. ) ;
  523. (void) RegDeleteValueW(
  524. WkstaKey,
  525. NW_GATEWAY_ENABLE
  526. ) ;
  527. (void) RegCloseKey( WkstaKey );
  528. }
  529. //
  530. // store new status if necessary
  531. //
  532. if (FinalStatus == NO_ERROR)
  533. FinalStatus = status ;
  534. //
  535. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  536. // \LanmanServer\Linkage
  537. //
  538. status = RegOpenKeyExW(
  539. HKEY_LOCAL_MACHINE,
  540. LMSERVER_LINKAGE_REGKEY,
  541. REG_OPTION_NON_VOLATILE, // options
  542. KEY_WRITE | KEY_READ, // desired access
  543. &ServerLinkageKey
  544. );
  545. if (status == ERROR_SUCCESS)
  546. {
  547. //
  548. // remove us from the OtherDependencies.
  549. // ignore read failures here (it may not be present)
  550. //
  551. status = NwReadRegValue(
  552. ServerLinkageKey,
  553. OTHERDEPS_VALUENAME,
  554. &OtherDeps
  555. );
  556. if (status == NO_ERROR)
  557. {
  558. //
  559. // this call munges the list to remove NWC if there.
  560. //
  561. RemoveNWCFromNullNullList(OtherDeps) ;
  562. status = RegSetValueExW(
  563. ServerLinkageKey,
  564. OTHERDEPS_VALUENAME,
  565. 0,
  566. REG_MULTI_SZ,
  567. (BYTE *)OtherDeps,
  568. CalcNullNullSize(OtherDeps) * sizeof(WCHAR)) ;
  569. (void) LocalFree(OtherDeps) ;
  570. (void) RemoveNwcDependency() ; // make this happen right away
  571. // ignore errors - reboot will fix
  572. }
  573. else
  574. {
  575. status = NO_ERROR ;
  576. }
  577. (void) RegCloseKey( ServerLinkageKey );
  578. }
  579. //
  580. // store new status if necessary
  581. //
  582. if (FinalStatus == NO_ERROR)
  583. FinalStatus = status ;
  584. return (FinalStatus) ;
  585. }
  586. DWORD
  587. NwpClearGatewayShare(
  588. IN LPWSTR ShareName
  589. )
  590. /*++
  591. Routine Description:
  592. This routine deletes a specific share from the remembered gateway
  593. shares in the registry.
  594. Arguments:
  595. ShareName - share value to delete
  596. Return Status:
  597. Win32 status code.
  598. --*/
  599. {
  600. DWORD status = NO_ERROR ;
  601. //
  602. // check that paramter is non null
  603. //
  604. if (ShareName)
  605. {
  606. HKEY hKey ;
  607. //
  608. //
  609. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  610. // \NWCWorkstation\Drives
  611. //
  612. status = RegOpenKeyExW(
  613. HKEY_LOCAL_MACHINE,
  614. NW_WORKSTATION_GATEWAY_SHARES,
  615. REG_OPTION_NON_VOLATILE, // options
  616. KEY_WRITE, // desired access
  617. &hKey
  618. );
  619. if ( status )
  620. return status ;
  621. status = RegDeleteValueW(
  622. hKey,
  623. ShareName
  624. ) ;
  625. (void) RegCloseKey( hKey );
  626. }
  627. else
  628. status = ERROR_INVALID_PARAMETER ;
  629. return status ;
  630. }
  631. typedef NET_API_STATUS (*PF_NETSHAREDEL) (
  632. LPWSTR server,
  633. LPWSTR name,
  634. DWORD reserved) ;
  635. #define NETSHAREDELSTICKY_API "NetShareDelSticky"
  636. #define NETSHAREDEL_API "NetShareDel"
  637. #define NETAPI_DLL L"NETAPI32"
  638. DWORD
  639. EnumAndDeleteShares(
  640. VOID
  641. )
  642. /*++
  643. Routine Description:
  644. This routine removes all persister share info in the server for
  645. all gateway shares.
  646. Arguments:
  647. None.
  648. Return Status:
  649. Win32 error code.
  650. --*/
  651. {
  652. DWORD err, i, type ;
  653. HKEY hKey = NULL ;
  654. FILETIME FileTime ;
  655. HANDLE hNetapi = NULL ;
  656. PF_NETSHAREDEL pfNetShareDel, pfNetShareDelSticky ;
  657. WCHAR Class[256], Share[NNLEN+1], Device[MAX_PATH+1] ;
  658. DWORD dwClass, dwSubKeys, dwMaxSubKey, dwMaxClass,
  659. dwValues, dwMaxValueName, dwMaxValueData, dwSDLength,
  660. dwShareLength, dwDeviceLength ;
  661. //
  662. // load the library so that not everyone needs link to netapi32
  663. //
  664. if (!(hNetapi = LoadLibraryW(NETAPI_DLL)))
  665. return (GetLastError()) ;
  666. //
  667. // get addresses of the 2 functions we are interested in
  668. //
  669. if (!(pfNetShareDel = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
  670. NETSHAREDEL_API)))
  671. {
  672. err = GetLastError() ;
  673. goto ExitPoint ;
  674. }
  675. if (!(pfNetShareDelSticky = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
  676. NETSHAREDELSTICKY_API)))
  677. {
  678. err = GetLastError() ;
  679. goto ExitPoint ;
  680. }
  681. //
  682. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  683. // \NWCGateway\Shares
  684. //
  685. err = RegOpenKeyExW(
  686. HKEY_LOCAL_MACHINE,
  687. NW_WORKSTATION_GATEWAY_SHARES,
  688. REG_OPTION_NON_VOLATILE, // options
  689. KEY_READ, // desired access
  690. &hKey
  691. );
  692. if ( err )
  693. goto ExitPoint ;
  694. //
  695. // read the info about that key
  696. //
  697. dwClass = sizeof(Class)/sizeof(Class[0]) ;
  698. err = RegQueryInfoKeyW(hKey,
  699. Class,
  700. &dwClass,
  701. NULL,
  702. &dwSubKeys,
  703. &dwMaxSubKey,
  704. &dwMaxClass,
  705. &dwValues,
  706. &dwMaxValueName,
  707. &dwMaxValueData,
  708. &dwSDLength,
  709. &FileTime) ;
  710. if ( err )
  711. {
  712. goto ExitPoint ;
  713. }
  714. //
  715. // for each value found, we have a share to delete
  716. //
  717. for (i = 0; i < dwValues; i++)
  718. {
  719. dwShareLength = sizeof(Share)/sizeof(Share[0]) ;
  720. dwDeviceLength = sizeof(Device) ;
  721. type = REG_SZ ;
  722. err = RegEnumValueW(hKey,
  723. i,
  724. Share,
  725. &dwShareLength,
  726. NULL,
  727. &type,
  728. (LPBYTE)Device,
  729. &dwDeviceLength) ;
  730. //
  731. // cleanup the share. try delete the share proper. if not
  732. // there, remove the sticky info instead.
  733. //
  734. if (!err)
  735. {
  736. err = (*pfNetShareDel)(NULL, Share, 0) ;
  737. if (err == NERR_NetNameNotFound)
  738. {
  739. (void) (*pfNetShareDelSticky)(NULL, Share, 0) ;
  740. }
  741. }
  742. //
  743. // ignore errors within the loop. we can to carry on to
  744. // cleanup as much as possible.
  745. //
  746. err = NO_ERROR ;
  747. }
  748. ExitPoint:
  749. if (hKey)
  750. (void) RegCloseKey( hKey );
  751. if (hNetapi)
  752. (void) FreeLibrary(hNetapi) ;
  753. return err ;
  754. }
  755. DWORD
  756. CalcNullNullSize(
  757. WCHAR *pszNullNull
  758. )
  759. /*++
  760. Routine Description:
  761. Walk thru a NULL NULL string, counting the number of
  762. characters, including the 2 nulls at the end.
  763. Arguments:
  764. Pointer to a NULL NULL string
  765. Return Status:
  766. Count of number of *characters*. See description.
  767. --*/
  768. {
  769. DWORD dwSize = 0 ;
  770. WCHAR *pszTmp = pszNullNull ;
  771. if (!pszNullNull)
  772. return 0 ;
  773. while (*pszTmp)
  774. {
  775. DWORD dwLen = wcslen(pszTmp) + 1 ;
  776. dwSize += dwLen ;
  777. pszTmp += dwLen ;
  778. }
  779. return (dwSize+1) ;
  780. }
  781. WCHAR *
  782. FindStringInNullNull(
  783. WCHAR *pszNullNull,
  784. WCHAR *pszString
  785. )
  786. /*++
  787. Routine Description:
  788. Walk thru a NULL NULL string, looking for the search string
  789. Arguments:
  790. pszNullNull: the string list we will search.
  791. pszString: what we are searching for.
  792. Return Status:
  793. The start of the string if found. Null, otherwise.
  794. --*/
  795. {
  796. WCHAR *pszTmp = pszNullNull ;
  797. if (!pszNullNull || !*pszNullNull)
  798. return NULL ;
  799. do {
  800. if (_wcsicmp(pszTmp,pszString)==0)
  801. return pszTmp ;
  802. pszTmp += wcslen(pszTmp) + 1 ;
  803. } while (*pszTmp) ;
  804. return NULL ;
  805. }
  806. VOID
  807. RemoveNWCFromNullNullList(
  808. WCHAR *OtherDeps
  809. )
  810. /*++
  811. Routine Description:
  812. Remove the NWCWorkstation string from a null null string.
  813. Arguments:
  814. OtherDeps: the string list we will munge.
  815. Return Status:
  816. None.
  817. --*/
  818. {
  819. LPWSTR pszTmp0, pszTmp1 ;
  820. //
  821. // find the NWCWorkstation string
  822. //
  823. pszTmp0 = FindStringInNullNull(OtherDeps, NW_WORKSTATION_SERVICE) ;
  824. if (!pszTmp0)
  825. return ;
  826. pszTmp1 = pszTmp0 + wcslen(pszTmp0) + 1 ; // skip past it
  827. //
  828. // shift the rest up
  829. //
  830. memmove(pszTmp0, pszTmp1, CalcNullNullSize(pszTmp1)*sizeof(WCHAR)) ;
  831. }
  832. DWORD RemoveNwcDependency(
  833. VOID
  834. )
  835. {
  836. SC_HANDLE ScManager = NULL;
  837. SC_HANDLE Service = NULL;
  838. LPQUERY_SERVICE_CONFIGW lpServiceConfig = NULL;
  839. DWORD err = NO_ERROR, dwBufferSize = 4096, dwBytesNeeded = 0;
  840. LPWSTR Deps = NULL ;
  841. lpServiceConfig = (LPQUERY_SERVICE_CONFIGW) LocalAlloc(LPTR, dwBufferSize) ;
  842. if (lpServiceConfig == NULL) {
  843. err = GetLastError();
  844. goto ExitPoint ;
  845. }
  846. ScManager = OpenSCManagerW(
  847. NULL,
  848. NULL,
  849. SC_MANAGER_CONNECT
  850. );
  851. if (ScManager == NULL) {
  852. err = GetLastError();
  853. goto ExitPoint ;
  854. }
  855. Service = OpenServiceW(
  856. ScManager,
  857. LANMAN_SERVER,
  858. (SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG)
  859. );
  860. if (Service == NULL) {
  861. err = GetLastError();
  862. goto ExitPoint ;
  863. }
  864. if (!QueryServiceConfigW(
  865. Service,
  866. lpServiceConfig, // address of service config. structure
  867. dwBufferSize, // size of service configuration buffer
  868. &dwBytesNeeded // address of variable for bytes needed
  869. )) {
  870. err = GetLastError();
  871. if (err == ERROR_INSUFFICIENT_BUFFER) {
  872. err = NO_ERROR ;
  873. dwBufferSize = dwBytesNeeded ;
  874. lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)
  875. LocalAlloc(LPTR, dwBufferSize) ;
  876. if (lpServiceConfig == NULL) {
  877. err = GetLastError();
  878. goto ExitPoint ;
  879. }
  880. if (!QueryServiceConfigW(
  881. Service,
  882. lpServiceConfig, // address of service config. structure
  883. dwBufferSize, // size of service configuration buffer
  884. &dwBytesNeeded // address of variable for bytes needed
  885. )) {
  886. err = GetLastError();
  887. }
  888. }
  889. if (err != NO_ERROR) {
  890. goto ExitPoint ;
  891. }
  892. }
  893. Deps = lpServiceConfig->lpDependencies ;
  894. RemoveNWCFromNullNullList(Deps) ;
  895. if (!ChangeServiceConfigW(
  896. Service,
  897. SERVICE_NO_CHANGE, // service type (no change)
  898. SERVICE_NO_CHANGE, // start type (no change)
  899. SERVICE_NO_CHANGE, // error control (no change)
  900. NULL, // binary path name (NULL for no change)
  901. NULL, // load order group (NULL for no change)
  902. NULL, // tag id (NULL for no change)
  903. Deps,
  904. NULL, // service start name (NULL for no change)
  905. NULL, // password (NULL for no change)
  906. NULL // display name (NULL for no change)
  907. )) {
  908. err = GetLastError();
  909. goto ExitPoint ;
  910. }
  911. ExitPoint:
  912. if (ScManager) {
  913. CloseServiceHandle(ScManager);
  914. }
  915. if (Service) {
  916. CloseServiceHandle(Service);
  917. }
  918. if (lpServiceConfig) {
  919. (void) LocalFree(lpServiceConfig) ;
  920. }
  921. return err ;
  922. }