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.

2991 lines
75 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. This module contains registry _access routines for the NT server
  7. service.
  8. Author:
  9. Chuck Lenzmeier (chuckl) 19-Mar-1992
  10. Revision History:
  11. --*/
  12. #include "srvsvcp.h"
  13. #include "ssreg.h"
  14. #include "srvconfg.h"
  15. #include <tstr.h>
  16. #include <netevent.h>
  17. //
  18. // Simple MIN and MAX macros. Watch out for side effects!
  19. //
  20. #define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
  21. #define MAX(a,b) ( ((a) < (b)) ? (b) : (a) )
  22. #define MAX_INTEGER_STRING 32
  23. #define MB * 1024 * 1024
  24. #define INF 0xffffffff
  25. //
  26. // ( u, n )
  27. // u is units to allocate for every n megabytes on a medium server.
  28. //
  29. #define CONFIG_TUPLE_SIZE 2
  30. typedef struct {
  31. DWORD initworkitems[CONFIG_TUPLE_SIZE];
  32. DWORD maxworkitems[CONFIG_TUPLE_SIZE];
  33. DWORD rawworkitems[CONFIG_TUPLE_SIZE];
  34. DWORD maxrawworkitems[CONFIG_TUPLE_SIZE];
  35. DWORD maxpagedmemoryusage[CONFIG_TUPLE_SIZE];
  36. DWORD maxnonpagedmemoryusage[CONFIG_TUPLE_SIZE];
  37. } CONFIG_SERVER_TABLE;
  38. CONFIG_SERVER_TABLE MedSrvCfgTbl = {
  39. //
  40. // ** NOTE ** : If the second column is greater than 4, then
  41. // you will need to add a check to make sure the statistic
  42. // did not drop to zero.
  43. //
  44. // Units / MB
  45. // Parameter
  46. // ---------
  47. //
  48. /* initworkitems */ { 1 , 4 },
  49. /* maxworkitems */ { 4 , 1 },
  50. /* rawworkitems */ { 1 , 4 },
  51. /* maxrawworkitems */ { 4 , 1 },
  52. /* maxpagedmemoryusage */ { 1 , 1 },
  53. /* maxnonpagedmemoryusage */ { 1 , 8 },
  54. };
  55. //
  56. // Minimum configuration system size is 8MB. Anything lower treated
  57. // as if 8 MB.
  58. //
  59. #define MIN_SYSTEM_SIZE 8
  60. //
  61. // A medium server reaches its max at 32M. A small server at 16M.
  62. //
  63. #define MAX_SMALL_SIZE 16
  64. #define MAX_MEDIUM_SIZE 32
  65. //
  66. // Note that the user limit is always -1 (unlimited). Autodisconnect
  67. // always defaults to 15 minutes.
  68. //
  69. //
  70. // Forward declarations
  71. //
  72. NTSTATUS
  73. EnumerateStickyShare (
  74. IN PWSTR ValueName,
  75. IN ULONG ValueType,
  76. IN PVOID ValueData,
  77. IN ULONG ValueLength,
  78. IN PVOID Context,
  79. IN PVOID EntryContext
  80. );
  81. NET_API_STATUS
  82. FillStickyShareInfo(
  83. IN PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo,
  84. IN PSHARE_INFO_502 Shi502
  85. );
  86. NTSTATUS
  87. GetSdFromRegistry(
  88. IN PWSTR ValueName,
  89. IN ULONG ValueType,
  90. IN PVOID ValueData,
  91. IN ULONG ValueLength,
  92. IN PVOID Context,
  93. IN PVOID EntryContext
  94. );
  95. BOOLEAN
  96. GetStickyShareInfo (
  97. IN PWSTR ValueName,
  98. IN ULONG ValueType,
  99. IN PVOID ValueData,
  100. OUT PUNICODE_STRING RemarkString,
  101. OUT PUNICODE_STRING PathString,
  102. OUT PSHARE_INFO_502 shi502,
  103. OUT PDWORD CacheState
  104. );
  105. LONG
  106. LoadParameters (
  107. PWCH Path
  108. );
  109. LONG
  110. LoadSizeParameter (
  111. VOID
  112. );
  113. NTSTATUS
  114. RecreateStickyShare (
  115. IN PWSTR ValueName,
  116. IN ULONG ValueType,
  117. IN PVOID ValueData,
  118. IN ULONG ValueLength,
  119. IN PVOID Context,
  120. IN PVOID EntryContext
  121. );
  122. NTSTATUS
  123. SaveSdToRegistry(
  124. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  125. IN PWSTR ShareName
  126. );
  127. NTSTATUS
  128. SetSizeParameters (
  129. IN PWSTR ValueName,
  130. IN ULONG ValueType,
  131. IN PVOID ValueData,
  132. IN ULONG ValueLength,
  133. IN PVOID Context,
  134. IN PVOID EntryContext
  135. );
  136. NTSTATUS
  137. SetStickyParameter (
  138. IN PWSTR ValueName,
  139. IN ULONG ValueType,
  140. IN PVOID ValueData,
  141. IN ULONG ValueLength,
  142. IN PVOID Context,
  143. IN PVOID EntryContext
  144. );
  145. #define IsPersonal() IsSuiteVersion(VER_SUITE_PERSONAL)
  146. #define IsWebBlade() IsSuiteVersion(VER_SUITE_BLADE)
  147. #define IsEmbedded() IsSuiteVersion(VER_SUITE_EMBEDDEDNT)
  148. BOOL
  149. IsSuiteVersion(USHORT SuiteMask)
  150. {
  151. OSVERSIONINFOEX Osvi;
  152. DWORD TypeMask;
  153. DWORDLONG ConditionMask;
  154. memset(&Osvi, 0, sizeof(OSVERSIONINFOEX));
  155. Osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  156. Osvi.wSuiteMask = SuiteMask;
  157. TypeMask = VER_SUITENAME;
  158. ConditionMask = 0;
  159. VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_OR);
  160. return(VerifyVersionInfo(&Osvi, TypeMask, ConditionMask));
  161. }
  162. ULONG
  163. SsRtlQueryEnvironmentLength (
  164. IN PVOID Environment
  165. )
  166. {
  167. PWCH p;
  168. ULONG length;
  169. p = Environment;
  170. ASSERT( p != NULL );
  171. //
  172. // The environment variable block consists of zero or more null
  173. // terminated ASCII strings. Each string is of the form:
  174. //
  175. // name=value
  176. //
  177. // where the null termination is after the value.
  178. //
  179. while ( *p ) {
  180. while ( *p ) {
  181. p++;
  182. }
  183. p++;
  184. }
  185. p++;
  186. length = (ULONG)((PCHAR)p - (PCHAR)Environment);
  187. //
  188. // Return accumulated length.
  189. //
  190. return length;
  191. }
  192. VOID
  193. SsAddParameterToRegistry (
  194. PFIELD_DESCRIPTOR Field,
  195. PVOID Value
  196. )
  197. {
  198. NTSTATUS status;
  199. PWCH valueName;
  200. DWORD valueType;
  201. LPBYTE valuePtr;
  202. DWORD valueDataLength;
  203. //
  204. // The value name is the parameter name and the value data is the
  205. // parameter value.
  206. //
  207. valueName = Field->FieldName;
  208. switch ( Field->FieldType ) {
  209. case BOOLEAN_FIELD:
  210. case DWORD_FIELD:
  211. valueType = REG_DWORD;
  212. valuePtr = Value;
  213. valueDataLength = sizeof(DWORD);
  214. break;
  215. case LPSTR_FIELD:
  216. valueType = REG_SZ;
  217. valuePtr = *(LPBYTE *)Value;
  218. if ( valuePtr != NULL ) {
  219. valueDataLength = SIZE_WSTR( (PWCH)valuePtr );
  220. } else {
  221. valueDataLength = 0;
  222. }
  223. break;
  224. }
  225. //
  226. // Set the value into the Parameters key.
  227. //
  228. status = RtlWriteRegistryValue(
  229. RTL_REGISTRY_SERVICES,
  230. PARAMETERS_REGISTRY_PATH,
  231. valueName,
  232. valueType,
  233. valuePtr,
  234. valueDataLength
  235. );
  236. if ( !NT_SUCCESS(status) ) {
  237. IF_DEBUG(REGISTRY) {
  238. SS_PRINT(( "SsAddParameterToRegistry: SetValue failed: %lx; "
  239. "parameter %ws won't stick\n", status, valueName ));
  240. }
  241. }
  242. return;
  243. } // SsAddParameterToRegistry
  244. VOID
  245. SsAddShareToRegistry (
  246. IN PSHARE_INFO_2 ShareInfo2,
  247. IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
  248. IN DWORD CacheState
  249. )
  250. {
  251. NTSTATUS status;
  252. PWCH valueName;
  253. PVOID environment;
  254. UNICODE_STRING nameString;
  255. UNICODE_STRING valueString;
  256. WCHAR integerString[MAX_INTEGER_STRING + 1];
  257. ULONG environmentLength;
  258. //
  259. // Build the value name and data strings. The value name is the
  260. // share name (netname), while the value data is share information
  261. // in REG_MULTI_SZ format. To build the value data, we use the
  262. // RTL environment routines.
  263. //
  264. valueName = ShareInfo2->shi2_netname;
  265. status = RtlCreateEnvironment( FALSE, &environment );
  266. if ( !NT_SUCCESS(status) ) {
  267. IF_DEBUG(REGISTRY) {
  268. SS_PRINT(( "SsAddShareToRegistry: CreateEnvironment failed: %lx; "
  269. "share %ws won't stick\n", status, valueName ));
  270. }
  271. goto exit1;
  272. }
  273. RtlInitUnicodeString( &nameString, PATH_VARIABLE_NAME );
  274. RtlInitUnicodeString( &valueString, ShareInfo2->shi2_path );
  275. status = RtlSetEnvironmentVariable(
  276. &environment,
  277. &nameString,
  278. &valueString
  279. );
  280. if ( !NT_SUCCESS(status) ) {
  281. IF_DEBUG(REGISTRY) {
  282. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  283. "share %s won't stick\n", status, valueName ));
  284. }
  285. goto exit2;
  286. }
  287. if ( ShareInfo2->shi2_remark != NULL ) {
  288. RtlInitUnicodeString( &nameString, REMARK_VARIABLE_NAME );
  289. RtlInitUnicodeString( &valueString, ShareInfo2->shi2_remark );
  290. status = RtlSetEnvironmentVariable(
  291. &environment,
  292. &nameString,
  293. &valueString
  294. );
  295. if ( !NT_SUCCESS(status) ) {
  296. IF_DEBUG(REGISTRY) {
  297. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  298. "share %s won't stick\n", status, valueName ));
  299. }
  300. goto exit2;
  301. }
  302. }
  303. RtlInitUnicodeString( &nameString, TYPE_VARIABLE_NAME );
  304. valueString.Buffer = integerString;
  305. valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
  306. status = RtlIntegerToUnicodeString(
  307. ShareInfo2->shi2_type,
  308. 10,
  309. &valueString
  310. );
  311. if ( !NT_SUCCESS(status) ) {
  312. IF_DEBUG(REGISTRY) {
  313. SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
  314. "share %ws won't stick\n", status, valueName ));
  315. }
  316. goto exit2;
  317. }
  318. status = RtlSetEnvironmentVariable(
  319. &environment,
  320. &nameString,
  321. &valueString
  322. );
  323. if ( !NT_SUCCESS(status) ) {
  324. IF_DEBUG(REGISTRY) {
  325. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  326. "share %s won't stick\n", status, valueName ));
  327. }
  328. goto exit2;
  329. }
  330. RtlInitUnicodeString( &nameString, PERMISSIONS_VARIABLE_NAME );
  331. valueString.Buffer = integerString;
  332. valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
  333. status = RtlIntegerToUnicodeString(
  334. ShareInfo2->shi2_permissions,
  335. 10,
  336. &valueString
  337. );
  338. if ( !NT_SUCCESS(status) ) {
  339. IF_DEBUG(REGISTRY) {
  340. SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
  341. "share %ws won't stick\n", status, valueName ));
  342. }
  343. goto exit2;
  344. }
  345. status = RtlSetEnvironmentVariable(
  346. &environment,
  347. &nameString,
  348. &valueString
  349. );
  350. if ( !NT_SUCCESS(status) ) {
  351. IF_DEBUG(REGISTRY) {
  352. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  353. "share %s won't stick\n", status, valueName ));
  354. }
  355. goto exit2;
  356. }
  357. RtlInitUnicodeString( &nameString, MAXUSES_VARIABLE_NAME );
  358. valueString.Buffer = integerString;
  359. valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
  360. status = RtlIntegerToUnicodeString(
  361. ShareInfo2->shi2_max_uses,
  362. 10,
  363. &valueString
  364. );
  365. if ( !NT_SUCCESS(status) ) {
  366. IF_DEBUG(REGISTRY) {
  367. SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
  368. "share %ws won't stick\n", status, valueName ));
  369. }
  370. goto exit2;
  371. }
  372. status = RtlSetEnvironmentVariable(
  373. &environment,
  374. &nameString,
  375. &valueString
  376. );
  377. if ( !NT_SUCCESS(status) ) {
  378. IF_DEBUG(REGISTRY) {
  379. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  380. "share %s won't stick\n", status, valueName ));
  381. }
  382. goto exit2;
  383. }
  384. //
  385. // Set the CacheState
  386. //
  387. RtlInitUnicodeString( &nameString, CSC_VARIABLE_NAME );
  388. valueString.Buffer = integerString;
  389. valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
  390. status = RtlIntegerToUnicodeString(
  391. CacheState,
  392. 10,
  393. &valueString
  394. );
  395. if( !NT_SUCCESS( status ) ) {
  396. IF_DEBUG(REGISTRY) {
  397. SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
  398. "share %ws won't stick\n", status, valueName ));
  399. }
  400. goto exit2;
  401. }
  402. status = RtlSetEnvironmentVariable(
  403. &environment,
  404. &nameString,
  405. &valueString
  406. );
  407. if ( !NT_SUCCESS(status) ) {
  408. IF_DEBUG(REGISTRY) {
  409. SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
  410. "share %s won't stick\n", status, valueName ));
  411. }
  412. goto exit2;
  413. }
  414. //
  415. // Set the value into the Shares key.
  416. //
  417. environmentLength = SsRtlQueryEnvironmentLength( environment );
  418. status = RtlWriteRegistryValue(
  419. RTL_REGISTRY_SERVICES,
  420. SHARES_REGISTRY_PATH,
  421. valueName,
  422. REG_MULTI_SZ,
  423. (LPBYTE)environment,
  424. environmentLength
  425. );
  426. if ( !NT_SUCCESS(status) ) {
  427. IF_DEBUG(REGISTRY) {
  428. SS_PRINT(( "SsAddShareToRegistry: SetValue failed: %lx; share %ws "
  429. "won't stick\n", status, valueName ));
  430. }
  431. }
  432. //
  433. // Save the file security descriptor
  434. //
  435. if ( ARGUMENT_PRESENT( SecurityDescriptor ) ) {
  436. status = SaveSdToRegistry(
  437. SecurityDescriptor,
  438. valueName
  439. );
  440. if ( !NT_SUCCESS(status) ) {
  441. IF_DEBUG(REGISTRY) {
  442. SS_PRINT(( "SsAddShareToRegistry: SaveSd failed: %lx; share %ws\n"
  443. , status, valueName ));
  444. }
  445. }
  446. }
  447. exit2:
  448. RtlDestroyEnvironment( environment );
  449. exit1:
  450. return;
  451. } // SsAddShareToRegistry
  452. NET_API_STATUS
  453. SsCheckRegistry (
  454. VOID
  455. )
  456. /*++
  457. Routine Description:
  458. This function verifies that the keys used by the server exist.
  459. Arguments:
  460. None.
  461. Return Value:
  462. NET_API_STATUS - success/failure of the operation.
  463. --*/
  464. {
  465. NTSTATUS status;
  466. LPWSTR subStrings[1];
  467. //
  468. // Verify the existence of the main server service key. If this
  469. // fails, the server service fails to start.
  470. //
  471. status = RtlCheckRegistryKey(
  472. RTL_REGISTRY_SERVICES,
  473. SERVER_REGISTRY_PATH
  474. );
  475. if ( !NT_SUCCESS(status) ) {
  476. subStrings[0] = SERVER_REGISTRY_PATH;
  477. SsLogEvent(
  478. EVENT_SRV_KEY_NOT_FOUND,
  479. 1,
  480. subStrings,
  481. RtlNtStatusToDosError( status )
  482. );
  483. IF_DEBUG(INITIALIZATION) {
  484. SS_PRINT(( "SsCheckRegistry: main key doesn't exist\n" ));
  485. }
  486. return ERROR_INVALID_PARAMETER; // !!! Need better error
  487. }
  488. //
  489. // Verify the existence of the Linkage subkey. If this fails, the
  490. // server service fails to start.
  491. //
  492. status = RtlCheckRegistryKey(
  493. RTL_REGISTRY_SERVICES,
  494. LINKAGE_REGISTRY_PATH
  495. );
  496. if ( !NT_SUCCESS(status) ) {
  497. subStrings[0] = LINKAGE_REGISTRY_PATH;
  498. SsLogEvent(
  499. EVENT_SRV_KEY_NOT_FOUND,
  500. 1,
  501. subStrings,
  502. RtlNtStatusToDosError( status )
  503. );
  504. IF_DEBUG(INITIALIZATION) {
  505. SS_PRINT(( "SsCheckRegistry: Linkage subkey doesn't exist\n" ));
  506. }
  507. return ERROR_INVALID_PARAMETER; // !!! Need better error
  508. }
  509. //
  510. // If the Parameters subkey doesn't exist, create it. If it can't
  511. // be created, fail to start the server.
  512. //
  513. status = RtlCheckRegistryKey(
  514. RTL_REGISTRY_SERVICES,
  515. PARAMETERS_REGISTRY_PATH
  516. );
  517. if ( !NT_SUCCESS(status) ) {
  518. status = RtlCreateRegistryKey(
  519. RTL_REGISTRY_SERVICES,
  520. PARAMETERS_REGISTRY_PATH
  521. );
  522. if ( !NT_SUCCESS(status) ) {
  523. subStrings[0] = PARAMETERS_REGISTRY_PATH;
  524. SsLogEvent(
  525. EVENT_SRV_KEY_NOT_CREATED,
  526. 1,
  527. subStrings,
  528. RtlNtStatusToDosError( status )
  529. );
  530. IF_DEBUG(INITIALIZATION) {
  531. SS_PRINT(( "SsCheckRegistry: Can't create Parameters subkey: "
  532. "%lx\n", status ));
  533. }
  534. return RtlNtStatusToDosError( status );
  535. }
  536. }
  537. //
  538. // Create the key holding the default security descriptors governing server APIs.
  539. // Since we have compiled-in versions for these APIs, it is a non-fatal error
  540. // if we cannot create this key. But we log it anyway.
  541. //
  542. status = RtlCheckRegistryKey(
  543. RTL_REGISTRY_SERVICES,
  544. SHARES_DEFAULT_SECURITY_REGISTRY_PATH
  545. );
  546. if ( !NT_SUCCESS(status) ) {
  547. status = RtlCreateRegistryKey(
  548. RTL_REGISTRY_SERVICES,
  549. SHARES_DEFAULT_SECURITY_REGISTRY_PATH
  550. );
  551. if ( !NT_SUCCESS(status) ) {
  552. subStrings[0] = SHARES_DEFAULT_SECURITY_REGISTRY_PATH;
  553. SsLogEvent(
  554. EVENT_SRV_KEY_NOT_CREATED,
  555. 1,
  556. subStrings,
  557. RtlNtStatusToDosError( status )
  558. );
  559. IF_DEBUG(INITIALIZATION) {
  560. SS_PRINT(( "SsCheckRegistry: Can't create DefaultSecurityRegistry subkey: "
  561. "%lx\n", status ));
  562. }
  563. }
  564. }
  565. {
  566. LONG error;
  567. HKEY handle;
  568. GUID Guid;
  569. //
  570. // Make sure the GUID_VARIABLE_NAME value is there and contains a valid GUID.
  571. //
  572. error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  573. FULL_PARAMETERS_REGISTRY_PATH,
  574. 0,
  575. KEY_ALL_ACCESS,
  576. &handle
  577. );
  578. if( error == ERROR_SUCCESS ) {
  579. DWORD type;
  580. DWORD size = sizeof( Guid );
  581. error = RegQueryValueEx( handle,
  582. GUID_VARIABLE_NAME,
  583. NULL,
  584. &type,
  585. (LPBYTE)&Guid,
  586. &size
  587. );
  588. if( error != ERROR_SUCCESS ||
  589. type != REG_BINARY ||
  590. size != sizeof( Guid ) ) {
  591. RPC_STATUS RpcStatus;
  592. //
  593. // We could not read it, or it's not a valid UUID.
  594. // Blow it away and reset
  595. //
  596. RegDeleteValue( handle, GUID_VARIABLE_NAME );
  597. RpcStatus = UuidCreate( &Guid );
  598. if( RpcStatus == RPC_S_OK || RpcStatus == RPC_S_UUID_LOCAL_ONLY ) {
  599. error = RegSetValueEx( handle,
  600. GUID_VARIABLE_NAME,
  601. 0,
  602. REG_BINARY,
  603. (LPBYTE)&Guid,
  604. sizeof( Guid )
  605. );
  606. }
  607. SsNotifyRdrOfGuid( &Guid );
  608. }
  609. RegCloseKey( handle );
  610. } else {
  611. RtlZeroMemory( &Guid, sizeof( Guid ) );
  612. }
  613. SsData.ServerInfo598.sv598_serverguid = Guid;
  614. }
  615. //
  616. // If the AutotunedParameters subkey doesn't exist, create it. If
  617. // it can't be created, fail to start the server.
  618. //
  619. status = RtlCheckRegistryKey(
  620. RTL_REGISTRY_SERVICES,
  621. AUTOTUNED_REGISTRY_PATH
  622. );
  623. if ( !NT_SUCCESS(status) ) {
  624. status = RtlCreateRegistryKey(
  625. RTL_REGISTRY_SERVICES,
  626. AUTOTUNED_REGISTRY_PATH
  627. );
  628. if ( !NT_SUCCESS(status) ) {
  629. subStrings[0] = AUTOTUNED_REGISTRY_PATH;
  630. SsLogEvent(
  631. EVENT_SRV_KEY_NOT_CREATED,
  632. 1,
  633. subStrings,
  634. RtlNtStatusToDosError( status )
  635. );
  636. IF_DEBUG(INITIALIZATION) {
  637. SS_PRINT(( "SsCheckRegistry: Can't create AutotunedParameters "
  638. "subkey: %lx\n", status ));
  639. }
  640. return RtlNtStatusToDosError( status );
  641. }
  642. }
  643. //
  644. // If the Shares subkey doesn't exist, create it. If it can't be
  645. // created, fail to start the server.
  646. //
  647. status = RtlCheckRegistryKey(
  648. RTL_REGISTRY_SERVICES,
  649. SHARES_REGISTRY_PATH
  650. );
  651. if ( !NT_SUCCESS(status) ) {
  652. status = RtlCreateRegistryKey(
  653. RTL_REGISTRY_SERVICES,
  654. SHARES_REGISTRY_PATH
  655. );
  656. if ( !NT_SUCCESS(status) ) {
  657. subStrings[0] = SHARES_REGISTRY_PATH;
  658. SsLogEvent(
  659. EVENT_SRV_KEY_NOT_CREATED,
  660. 1,
  661. subStrings,
  662. RtlNtStatusToDosError( status )
  663. );
  664. IF_DEBUG(INITIALIZATION) {
  665. SS_PRINT(( "SsCheckRegistry: Can't create Shares subkey: "
  666. "%lx\n", status ));
  667. }
  668. return RtlNtStatusToDosError( status );
  669. }
  670. }
  671. //
  672. // If the Shares Security subkey doesn't exist, create it. If it
  673. // can't be created, fail to start the server.
  674. //
  675. status = RtlCheckRegistryKey(
  676. RTL_REGISTRY_SERVICES,
  677. SHARES_SECURITY_REGISTRY_PATH
  678. );
  679. if ( !NT_SUCCESS(status) ) {
  680. status = RtlCreateRegistryKey(
  681. RTL_REGISTRY_SERVICES,
  682. SHARES_SECURITY_REGISTRY_PATH
  683. );
  684. if ( !NT_SUCCESS(status) ) {
  685. subStrings[0] = SHARES_SECURITY_REGISTRY_PATH;
  686. SsLogEvent(
  687. EVENT_SRV_KEY_NOT_CREATED,
  688. 1,
  689. subStrings,
  690. RtlNtStatusToDosError( status )
  691. );
  692. IF_DEBUG(INITIALIZATION) {
  693. SS_PRINT(( "SsCheckRegistry: Can't create Shares Security subkey: "
  694. "%lx\n", status ));
  695. }
  696. return RtlNtStatusToDosError( status );
  697. }
  698. }
  699. //
  700. // All keys successfully checked.
  701. //
  702. return NO_ERROR;
  703. } // SsCheckRegistry
  704. NET_API_STATUS
  705. SsEnumerateStickyShares (
  706. IN OUT PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo
  707. )
  708. /*++
  709. Routine Description:
  710. Reads the registry to find and return sticky shares.
  711. Arguments:
  712. ShareEnumInfo - points to a structure that contains the parameters
  713. to the NetShareEnumSticky call.
  714. Return Value:
  715. NET_API_STATUS - success/failure of the operation.
  716. --*/
  717. {
  718. NTSTATUS status;
  719. PRTL_QUERY_REGISTRY_TABLE queryTable;
  720. ShareEnumInfo->TotalBytesNeeded = 0;
  721. ShareEnumInfo->TotalEntries = 0;
  722. ShareEnumInfo->EntriesRead = 0;
  723. //
  724. // Initialize the reserve fields. This tells the callback routine,
  725. // how many times it has been called.
  726. //
  727. ShareEnumInfo->ShareEnumIndex = 0;
  728. ShareEnumInfo->StartOfFixedData = (PCHAR)ShareEnumInfo->OutputBuffer;
  729. ShareEnumInfo->EndOfVariableData = (PCHAR)ShareEnumInfo->OutputBuffer +
  730. ShareEnumInfo->OutputBufferLength;
  731. //
  732. // We need to align it since we deal with unicode strings.
  733. //
  734. ShareEnumInfo->EndOfVariableData =
  735. (PCHAR)((ULONG_PTR)ShareEnumInfo->EndOfVariableData & ~1);
  736. //
  737. // Ask the RTL to call us back for each value in the Shares key.
  738. //
  739. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  740. if ( queryTable != NULL ) {
  741. queryTable[0].QueryRoutine = EnumerateStickyShare;
  742. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  743. queryTable[0].Name = NULL;
  744. queryTable[0].EntryContext = NULL;
  745. queryTable[0].DefaultType = REG_NONE;
  746. queryTable[0].DefaultData = NULL;
  747. queryTable[0].DefaultLength = 0;
  748. queryTable[1].QueryRoutine = NULL;
  749. queryTable[1].Flags = 0;
  750. queryTable[1].Name = NULL;
  751. status = RtlQueryRegistryValues(
  752. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  753. SHARES_REGISTRY_PATH,
  754. queryTable,
  755. ShareEnumInfo,
  756. NULL
  757. );
  758. MIDL_user_free( queryTable );
  759. } else {
  760. status = STATUS_INSUFFICIENT_RESOURCES;
  761. }
  762. if ( !NT_SUCCESS(status) ) {
  763. IF_DEBUG(INITIALIZATION) {
  764. SS_PRINT(( "SsEnumerateStickyShares: RtlQueryRegistryValues "
  765. "failed: %lx\n", status ));
  766. }
  767. return RtlNtStatusToDosError( status );
  768. }
  769. return NO_ERROR;
  770. } // SsEnumerateStickyShares
  771. NET_API_STATUS
  772. SsLoadConfigurationParameters (
  773. VOID
  774. )
  775. /*++
  776. Routine Description:
  777. Reads the registry to get server configuration parameters. These
  778. server parameters must be set before the server FSP has been
  779. started.
  780. Arguments:
  781. None.
  782. Return Value:
  783. NET_API_STATUS - success/failure of the operation.
  784. --*/
  785. {
  786. LONG error;
  787. //
  788. // Get the basic Size parameter, then load autotuned parameters,
  789. // then load manually set parameters. This ordering allows manual
  790. // settings to override autotuning.
  791. //
  792. error = LoadSizeParameter( );
  793. if ( error == NO_ERROR ) {
  794. error = LoadParameters( AUTOTUNED_REGISTRY_PATH );
  795. if ( error == NO_ERROR ) {
  796. error = LoadParameters( PARAMETERS_REGISTRY_PATH );
  797. }
  798. }
  799. //
  800. // The copy read to MDL read switchover must occur at or below the
  801. // SMB buffer size.
  802. //
  803. SsData.ServerInfo598.sv598_mdlreadswitchover =
  804. MIN(
  805. SsData.ServerInfo598.sv598_mdlreadswitchover,
  806. SsData.ServerInfo599.sv599_sizreqbuf);
  807. //
  808. // If they want to require security signatures, it implies enabling them
  809. //
  810. if( SsData.ServerInfo598.sv598_requiresecuritysignature )
  811. {
  812. SsData.ServerInfo598.sv598_enablesecuritysignature = TRUE;
  813. }
  814. //
  815. // Override parameters that cannot be set on WinNT (vs. NTAS).
  816. //
  817. // The server itself also performs most of these overrides, in case
  818. // somebody figures out the FSCTL that changes parameters. We also
  819. // override in the service in order to keep the service's view
  820. // consistent with the server's. If you make any changes here, also
  821. // make them in srv\svcsrv.c.
  822. //
  823. // Embedded does its own parameter validation, so skip it here
  824. if( !IsEmbedded() )
  825. {
  826. if ( SsData.ServerInfo598.sv598_producttype == NtProductWinNt ) {
  827. //
  828. // On WinNT, the maximum value of certain parameters is fixed at
  829. // build time. These include: concurrent users, SMB buffers,
  830. // and threads.
  831. //
  832. #define MINIMIZE(_param,_max) _param = MIN( _param, _max );
  833. MINIMIZE( SsData.ServerInfo102.sv102_users, MAX_USERS_WKSTA );
  834. MINIMIZE( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS_WKSTA );
  835. MINIMIZE( SsData.ServerInfo598.sv598_maxthreadsperqueue, MAX_THREADS_WKSTA );
  836. SsData.ServerInfo599.sv599_maxmpxct = DEF_MAXMPXCT_WKSTA;
  837. if( IsPersonal() )
  838. {
  839. MINIMIZE( SsData.ServerInfo102.sv102_users, MAX_USERS_PERSONAL );
  840. }
  841. //
  842. // On WinNT, we do not cache closed RFCBs.
  843. //
  844. SsData.ServerInfo598.sv598_cachedopenlimit = 0;
  845. //
  846. // Sharing of redirected drives is not allowed on WinNT.
  847. //
  848. SsData.ServerInfo599.sv599_enablesharednetdrives = FALSE;
  849. }
  850. if( IsWebBlade() )
  851. {
  852. MINIMIZE( SsData.ServerInfo102.sv102_users, MAX_USERS_WEB_BLADE );
  853. MINIMIZE( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS_WKSTA );
  854. MINIMIZE( SsData.ServerInfo598.sv598_maxthreadsperqueue, MAX_THREADS_WKSTA );
  855. }
  856. }
  857. else
  858. {
  859. // If this is a Class 1 basic embedded device, keep our memory consumption lower too
  860. if( SsData.ServerInfo102.sv102_users == MAX_USERS_EMBEDDED )
  861. {
  862. MINIMIZE( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS_EMBEDDED );
  863. MINIMIZE( SsData.ServerInfo598.sv598_maxthreadsperqueue, MAX_THREADS_EMBEDDED );
  864. SsData.ServerInfo599.sv599_maxmpxct = DEF_MAXMPXCT_EMBEDDED;
  865. }
  866. }
  867. return error;
  868. } // SsLoadConfigurationParameters
  869. NET_API_STATUS
  870. SsRecreateStickyShares (
  871. VOID
  872. )
  873. /*++
  874. Routine Description:
  875. Reads the registry to find and create sticky shares.
  876. Arguments:
  877. None.
  878. Return Value:
  879. NET_API_STATUS - success/failure of the operation.
  880. --*/
  881. {
  882. NTSTATUS status;
  883. PRTL_QUERY_REGISTRY_TABLE queryTable;
  884. ULONG IterationCount = 0;
  885. //
  886. // Ask the RTL to call us back for each value in the Shares key.
  887. //
  888. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  889. if ( queryTable != NULL ) {
  890. queryTable[0].QueryRoutine = RecreateStickyShare;
  891. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  892. queryTable[0].Name = NULL;
  893. queryTable[0].EntryContext = NULL;
  894. queryTable[0].DefaultType = REG_NONE;
  895. queryTable[0].DefaultData = NULL;
  896. queryTable[0].DefaultLength = 0;
  897. queryTable[1].QueryRoutine = NULL;
  898. queryTable[1].Flags = 0;
  899. queryTable[1].Name = NULL;
  900. status = RtlQueryRegistryValues(
  901. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  902. SHARES_REGISTRY_PATH,
  903. queryTable,
  904. &IterationCount,
  905. NULL
  906. );
  907. MIDL_user_free( queryTable );
  908. } else {
  909. status = STATUS_INSUFFICIENT_RESOURCES;
  910. }
  911. if ( !NT_SUCCESS(status) ) {
  912. IF_DEBUG(INITIALIZATION) {
  913. SS_PRINT(( "SsRecreateStickyShares: RtlQueryRegistryValues "
  914. "failed: %lx\n", status ));
  915. }
  916. return RtlNtStatusToDosError( status );
  917. }
  918. return NO_ERROR;
  919. } // SsRecreateStickyShares
  920. NET_API_STATUS
  921. SsRemoveShareFromRegistry (
  922. LPWSTR NetName
  923. )
  924. {
  925. NET_API_STATUS error = NO_ERROR;
  926. NTSTATUS status;
  927. PWCH valueName;
  928. //
  929. // The value name is the share name. Remove that value from the
  930. // Shares key.
  931. //
  932. valueName = NetName;
  933. //
  934. // Delete the share security
  935. //
  936. status = RtlDeleteRegistryValue(
  937. RTL_REGISTRY_SERVICES,
  938. SHARES_SECURITY_REGISTRY_PATH,
  939. valueName
  940. );
  941. if ( !NT_SUCCESS(status) ) {
  942. IF_DEBUG(REGISTRY) {
  943. SS_PRINT(( "SsRemoveShareFromRegistry: Delete Security value failed: %lx; "
  944. "share %ws will return\n", status, valueName ));
  945. }
  946. }
  947. //
  948. // Delete the share
  949. //
  950. status = RtlDeleteRegistryValue(
  951. RTL_REGISTRY_SERVICES,
  952. SHARES_REGISTRY_PATH,
  953. valueName
  954. );
  955. if ( !NT_SUCCESS(status) ) {
  956. IF_DEBUG(REGISTRY) {
  957. SS_PRINT(( "SsRemoveShareFromRegistry: DeleteValue failed: %lx; "
  958. "share %ws will return\n", status, valueName ));
  959. }
  960. error = RtlNtStatusToDosError( status );
  961. }
  962. return error;
  963. } // SsRemoveShareFromRegistry
  964. VOID
  965. BindToTransport (
  966. IN LPWSTR TransportName
  967. )
  968. {
  969. NET_API_STATUS error;
  970. SERVER_TRANSPORT_INFO_0 svti0;
  971. RtlZeroMemory( &svti0, sizeof( svti0 ) );
  972. svti0.svti0_transportname = TransportName;
  973. svti0.svti0_transportaddress = SsData.SsServerTransportAddress;
  974. svti0.svti0_transportaddresslength =
  975. ComputeTransportAddressClippedLength(
  976. SsData.SsServerTransportAddress,
  977. SsData.SsServerTransportAddressLength );
  978. //
  979. // Bind to the transport.
  980. //
  981. IF_DEBUG(INITIALIZATION) {
  982. SS_PRINT(( "BindToTransport: binding to transport %ws\n", TransportName ));
  983. }
  984. error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&svti0 );
  985. if ( error != NO_ERROR ) {
  986. DWORD eventId;
  987. LPWSTR subStrings[2];
  988. IF_DEBUG(INITIALIZATION_ERRORS) {
  989. SS_PRINT(( "SsBindToTransports: failed to bind to %ws: "
  990. "%ld\n", TransportName, error ));
  991. }
  992. eventId = (error == ERROR_DUP_NAME || error == ERROR_INVALID_NETNAME ) ?
  993. EVENT_SRV_CANT_BIND_DUP_NAME :
  994. EVENT_SRV_CANT_BIND_TO_TRANSPORT;
  995. subStrings[0] = TransportName;
  996. SsLogEvent(
  997. eventId,
  998. 1,
  999. subStrings,
  1000. error
  1001. );
  1002. }
  1003. } // BindToTransport
  1004. NTSTATUS
  1005. BindOptionalNameToTransport (
  1006. IN PWSTR ValueName,
  1007. IN ULONG ValueType,
  1008. IN PVOID ValueData,
  1009. IN ULONG ValueLength,
  1010. IN PVOID Context,
  1011. IN PVOID EntryContext
  1012. )
  1013. {
  1014. SERVER_TRANSPORT_INFO_0 sti;
  1015. UCHAR serverName[ MAX_PATH ];
  1016. UNICODE_STRING UnicodeName;
  1017. NET_API_STATUS error;
  1018. LPWSTR subStrings[2];
  1019. ULONG namelen;
  1020. subStrings[0] = (LPWSTR)ValueData;
  1021. subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
  1022. if( ValueType != REG_SZ ) {
  1023. //
  1024. // Not a string!
  1025. //
  1026. SsLogEvent(
  1027. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1028. 2,
  1029. subStrings,
  1030. NO_ERROR
  1031. );
  1032. return STATUS_SUCCESS;
  1033. }
  1034. UnicodeName.Length = wcslen( (LPWSTR)ValueData ) * sizeof( WCHAR );
  1035. UnicodeName.MaximumLength = UnicodeName.Length + sizeof( WCHAR );
  1036. UnicodeName.Buffer = (LPWSTR)ValueData;
  1037. error = ConvertStringToTransportAddress( &UnicodeName, serverName, &namelen );
  1038. if( error != NO_ERROR ) {
  1039. //
  1040. // Invalid server name!
  1041. //
  1042. SsLogEvent(
  1043. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1044. 2,
  1045. subStrings,
  1046. error
  1047. );
  1048. return STATUS_SUCCESS;
  1049. }
  1050. RtlZeroMemory( &sti, sizeof(sti) );
  1051. sti.svti0_transportname = (LPWSTR)Context;
  1052. sti.svti0_transportaddress = serverName;
  1053. sti.svti0_transportaddresslength = namelen;
  1054. error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&sti );
  1055. if ( error != NO_ERROR ) {
  1056. //
  1057. // Could not register the name!
  1058. //
  1059. subStrings[0] = (LPWSTR)ValueData;
  1060. subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
  1061. SsLogEvent(
  1062. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1063. 2,
  1064. subStrings,
  1065. error
  1066. );
  1067. }
  1068. return STATUS_SUCCESS;
  1069. }
  1070. VOID
  1071. BindOptionalNames (
  1072. IN PWSTR TransportName
  1073. )
  1074. {
  1075. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1076. NTSTATUS status;
  1077. //
  1078. // We need to iterate over the optional names and bind them to this
  1079. // transport.
  1080. //
  1081. //
  1082. // Now see if there any optional bindings we should perform
  1083. //
  1084. queryTable[0].QueryRoutine = BindOptionalNameToTransport;
  1085. queryTable[0].Flags = 0;
  1086. queryTable[0].Name = OPTIONAL_NAMES_VALUE_NAME;
  1087. queryTable[0].EntryContext = NULL;
  1088. queryTable[0].DefaultType = REG_NONE;
  1089. queryTable[0].DefaultData = NULL;
  1090. queryTable[0].DefaultLength = 0;
  1091. queryTable[1].QueryRoutine = NULL;
  1092. queryTable[1].Flags = 0;
  1093. queryTable[1].Name = NULL;
  1094. (void)RtlQueryRegistryValues(
  1095. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1096. PARAMETERS_REGISTRY_PATH,
  1097. queryTable,
  1098. TransportName,
  1099. NULL
  1100. );
  1101. } // BindOptionalNames
  1102. NTSTATUS
  1103. EnumerateStickyShare (
  1104. IN PWSTR ValueName,
  1105. IN ULONG ValueType,
  1106. IN PVOID ValueData,
  1107. IN ULONG ValueLength,
  1108. IN PVOID Context,
  1109. IN PVOID EntryContext
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Callback routine for SsEnumerateStickyShare. Routine will get information
  1114. on share and fill in the output buffer.
  1115. Arguments:
  1116. ValueName - Name of the share
  1117. ValueType - Value type of the share name.
  1118. ValueData - Data associated with the ValueName.
  1119. Context - Pointer to our enum information structure.
  1120. Return Value:
  1121. NET_API_STATUS - success/failure of the operation.
  1122. --*/
  1123. {
  1124. NET_API_STATUS error;
  1125. SHARE_INFO_502 shi502;
  1126. UNICODE_STRING pathString;
  1127. UNICODE_STRING remarkString;
  1128. PSRVSVC_SHARE_ENUM_INFO enumInfo = (PSRVSVC_SHARE_ENUM_INFO) Context;
  1129. DWORD cacheState;
  1130. ValueLength, EntryContext;
  1131. remarkString.Buffer = NULL;
  1132. pathString.Buffer = NULL;
  1133. if ( GetStickyShareInfo(
  1134. ValueName,
  1135. ValueType,
  1136. ValueData,
  1137. &remarkString,
  1138. &pathString,
  1139. &shi502,
  1140. &cacheState
  1141. ) ) {
  1142. //
  1143. // Do the actual add of the share.
  1144. //
  1145. IF_DEBUG(REGISTRY) {
  1146. SS_PRINT(( "EnumerateStickyShares: adding share %ws\n", ValueName ));
  1147. }
  1148. shi502.shi502_remark = remarkString.Buffer;
  1149. shi502.shi502_path = pathString.Buffer;
  1150. //
  1151. // Skip until we have the right share to resume from
  1152. //
  1153. if ( (enumInfo->TotalEntries == 0) &&
  1154. (enumInfo->ShareEnumIndex < enumInfo->ResumeHandle) ) {
  1155. enumInfo->ShareEnumIndex++;
  1156. } else {
  1157. enumInfo->TotalEntries++;
  1158. error = FillStickyShareInfo( enumInfo, &shi502 );
  1159. if ( error != NO_ERROR ) {
  1160. IF_DEBUG(REGISTRY) {
  1161. SS_PRINT(( "EnumerateStickyShares: failed to add share "
  1162. "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
  1163. }
  1164. } else {
  1165. enumInfo->EntriesRead++;
  1166. enumInfo->ResumeHandle++;
  1167. }
  1168. }
  1169. //
  1170. // free buffers allocated by GetStickyShareInfo
  1171. //
  1172. if ( remarkString.Buffer != NULL ) {
  1173. RtlFreeUnicodeString( &remarkString );
  1174. }
  1175. if ( pathString.Buffer != NULL ) {
  1176. RtlFreeUnicodeString( &pathString );
  1177. }
  1178. if ( shi502.shi502_security_descriptor != NULL ) {
  1179. MIDL_user_free( shi502.shi502_security_descriptor );
  1180. }
  1181. }
  1182. return STATUS_SUCCESS;
  1183. } // EnumerateStickyShare
  1184. NTSTATUS
  1185. GetSdFromRegistry(
  1186. IN PWSTR ValueName,
  1187. IN ULONG ValueType,
  1188. IN PVOID ValueData,
  1189. IN ULONG ValueLength,
  1190. IN PVOID Context,
  1191. IN PVOID EntryContext
  1192. )
  1193. {
  1194. NTSTATUS status = STATUS_SUCCESS;
  1195. PSECURITY_DESCRIPTOR fileSD = NULL;
  1196. PSHARE_INFO_502 shi502 = (PSHARE_INFO_502) Context;
  1197. LPWSTR subStrings[1];
  1198. EntryContext, ValueName, ValueType;
  1199. if ( ValueLength > 0 ) {
  1200. fileSD = MIDL_user_allocate( ValueLength );
  1201. if ( fileSD == NULL) {
  1202. status = STATUS_INSUFFICIENT_RESOURCES;
  1203. } else {
  1204. RtlCopyMemory(
  1205. fileSD,
  1206. ValueData,
  1207. ValueLength
  1208. );
  1209. if ( !RtlValidSecurityDescriptor( fileSD ) ) {
  1210. subStrings[0] = ValueName;
  1211. SsLogEvent(
  1212. EVENT_SRV_INVALID_SD,
  1213. 1,
  1214. subStrings,
  1215. RtlNtStatusToDosError( status )
  1216. );
  1217. MIDL_user_free( fileSD );
  1218. fileSD = NULL;
  1219. status = STATUS_INVALID_SECURITY_DESCR;
  1220. }
  1221. }
  1222. }
  1223. shi502->shi502_security_descriptor = fileSD;
  1224. return(status);
  1225. } // GetSdFromRegistry
  1226. BOOLEAN
  1227. GetStickyShareInfo (
  1228. IN PWSTR ValueName,
  1229. IN ULONG ValueType,
  1230. IN PVOID ValueData,
  1231. OUT PUNICODE_STRING RemarkString,
  1232. OUT PUNICODE_STRING PathString,
  1233. OUT PSHARE_INFO_502 shi502,
  1234. OUT PDWORD CacheState
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. Gets share information from the registry.
  1239. Arguments:
  1240. ValueName - Name of the share
  1241. ValueType - Value type of the share name.
  1242. ValueData - Data associated with the ValueName.
  1243. RemarkString - Upon return, points to a unicode string containing the
  1244. user remark for this share.
  1245. PathString - Upon return, points to a unicode string containing the
  1246. path for this share.
  1247. shi502 - Upon return, points to a unicode string containing a
  1248. SHARE_INFO_502 structure.
  1249. Return Value:
  1250. TRUE, if share information successfully retrieved.
  1251. FALSE, otherwise.
  1252. --*/
  1253. {
  1254. NTSTATUS status;
  1255. UNICODE_STRING variableNameString;
  1256. WCHAR integerStringBuffer[35];
  1257. UNICODE_STRING unicodeString;
  1258. LPWSTR subStrings[2];
  1259. PathString->Buffer = NULL;
  1260. RemarkString->Buffer = NULL;
  1261. shi502->shi502_security_descriptor = NULL;
  1262. shi502->shi502_path = NULL;
  1263. shi502->shi502_remark = NULL;
  1264. shi502->shi502_reserved = 0;
  1265. //
  1266. // Because the NT server doesn't support share-level security, the
  1267. // password is always NULL.
  1268. //
  1269. shi502->shi502_passwd = NULL;
  1270. //
  1271. // The value type must be REG_MULTI_SZ, and the value name must not
  1272. // be null.
  1273. //
  1274. if ( (ValueType != REG_MULTI_SZ) ||
  1275. (wcslen(ValueName) == 0) ) {
  1276. subStrings[0] = ValueName;
  1277. subStrings[1] = SHARES_REGISTRY_PATH;
  1278. SsLogEvent(
  1279. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1280. 2,
  1281. subStrings,
  1282. NO_ERROR
  1283. );
  1284. IF_DEBUG(REGISTRY) {
  1285. SS_PRINT(( "GetStickyShareInfo: skipping invalid value %ws\n",
  1286. ValueName ));
  1287. }
  1288. goto errorexit;
  1289. }
  1290. //
  1291. // The share name is the value name. The value data describes the
  1292. // rest of the information about the share.
  1293. //
  1294. shi502->shi502_netname = ValueName;
  1295. //
  1296. // The REG_MULTI_SZ format is the same as that used for storing
  1297. // environment variables. Find known share parameters in the data.
  1298. //
  1299. // Get the share path. It must be present.
  1300. //
  1301. RtlInitUnicodeString( &variableNameString, PATH_VARIABLE_NAME );
  1302. PathString->MaximumLength = 0;
  1303. status = RtlQueryEnvironmentVariable_U(
  1304. ValueData,
  1305. &variableNameString,
  1306. PathString
  1307. );
  1308. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1309. //
  1310. // The path is not specified. Ignore this share.
  1311. //
  1312. subStrings[0] = ValueName;
  1313. subStrings[1] = SHARES_REGISTRY_PATH;
  1314. SsLogEvent(
  1315. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1316. 2,
  1317. subStrings,
  1318. RtlNtStatusToDosError( status )
  1319. );
  1320. IF_DEBUG(REGISTRY) {
  1321. SS_PRINT(( "GetStickyShareInfo: No path; ignoring share.\n" ));
  1322. }
  1323. goto errorexit;
  1324. }
  1325. PathString->MaximumLength = (USHORT)(PathString->Length + sizeof(WCHAR));
  1326. PathString->Buffer = MIDL_user_allocate( PathString->MaximumLength );
  1327. if ( PathString->Buffer == NULL ) {
  1328. //
  1329. // No space for path. Ignore this share.
  1330. //
  1331. subStrings[0] = ValueName;
  1332. subStrings[1] = SHARES_REGISTRY_PATH;
  1333. SsLogEvent(
  1334. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1335. 2,
  1336. subStrings,
  1337. ERROR_NOT_ENOUGH_MEMORY
  1338. );
  1339. IF_DEBUG(REGISTRY) {
  1340. SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
  1341. "share.\n" ));
  1342. }
  1343. goto errorexit;
  1344. }
  1345. status = RtlQueryEnvironmentVariable_U(
  1346. ValueData,
  1347. &variableNameString,
  1348. PathString
  1349. );
  1350. if ( !NT_SUCCESS(status) ) {
  1351. //
  1352. // Huh? The second attempt failed. Ignore this share.
  1353. //
  1354. subStrings[0] = ValueName;
  1355. subStrings[1] = SHARES_REGISTRY_PATH;
  1356. SsLogEvent(
  1357. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1358. 2,
  1359. subStrings,
  1360. RtlNtStatusToDosError( status )
  1361. );
  1362. IF_DEBUG(REGISTRY) {
  1363. SS_PRINT(( "GetStickyShareInfo: Second query failed! Ignoring "
  1364. "share.\n" ));
  1365. }
  1366. goto errorexit;
  1367. }
  1368. //
  1369. // Get the remark. It may be omitted.
  1370. //
  1371. RtlInitUnicodeString( &variableNameString, REMARK_VARIABLE_NAME );
  1372. RemarkString->MaximumLength = 0;
  1373. status = RtlQueryEnvironmentVariable_U(
  1374. ValueData,
  1375. &variableNameString,
  1376. RemarkString
  1377. );
  1378. if ( status == STATUS_BUFFER_TOO_SMALL ) {
  1379. RemarkString->MaximumLength =
  1380. (USHORT)(RemarkString->Length + sizeof(WCHAR));
  1381. RemarkString->Buffer =
  1382. MIDL_user_allocate( RemarkString->MaximumLength );
  1383. if ( RemarkString->Buffer == NULL ) {
  1384. //
  1385. // No space for remark. Ignore this share.
  1386. //
  1387. subStrings[0] = ValueName;
  1388. subStrings[1] = SHARES_REGISTRY_PATH;
  1389. SsLogEvent(
  1390. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1391. 2,
  1392. subStrings,
  1393. ERROR_NOT_ENOUGH_MEMORY
  1394. );
  1395. IF_DEBUG(REGISTRY) {
  1396. SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
  1397. "share.\n" ));
  1398. }
  1399. goto errorexit;
  1400. }
  1401. status = RtlQueryEnvironmentVariable_U(
  1402. ValueData,
  1403. &variableNameString,
  1404. RemarkString
  1405. );
  1406. if ( !NT_SUCCESS(status) ) {
  1407. //
  1408. // Huh? The second attempt failed. Ignore this share.
  1409. //
  1410. subStrings[0] = ValueName;
  1411. subStrings[1] = SHARES_REGISTRY_PATH;
  1412. SsLogEvent(
  1413. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1414. 2,
  1415. subStrings,
  1416. RtlNtStatusToDosError( status )
  1417. );
  1418. IF_DEBUG(REGISTRY) {
  1419. SS_PRINT(( "GetStickyShareInfo: Second query failed! "
  1420. "Ignoring share.\n" ));
  1421. }
  1422. goto errorexit;
  1423. }
  1424. }
  1425. //
  1426. // Get the share type. It may be omitted.
  1427. //
  1428. RtlInitUnicodeString( &variableNameString, TYPE_VARIABLE_NAME );
  1429. unicodeString.Buffer = integerStringBuffer;
  1430. unicodeString.MaximumLength = 35;
  1431. status = RtlQueryEnvironmentVariable_U(
  1432. ValueData,
  1433. &variableNameString,
  1434. &unicodeString
  1435. );
  1436. if ( !NT_SUCCESS(status) ) {
  1437. shi502->shi502_type = STYPE_DISKTREE;
  1438. } else {
  1439. status = RtlUnicodeStringToInteger(
  1440. &unicodeString,
  1441. 0,
  1442. &shi502->shi502_type
  1443. );
  1444. if ( !NT_SUCCESS(status) ) {
  1445. subStrings[0] = ValueName;
  1446. subStrings[1] = SHARES_REGISTRY_PATH;
  1447. SsLogEvent(
  1448. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1449. 2,
  1450. subStrings,
  1451. RtlNtStatusToDosError( status )
  1452. );
  1453. IF_DEBUG(REGISTRY) {
  1454. SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
  1455. "%lx\n", status ));
  1456. }
  1457. goto errorexit;
  1458. }
  1459. }
  1460. //
  1461. // Get the share permissions. It may be omitted.
  1462. //
  1463. RtlInitUnicodeString( &variableNameString, PERMISSIONS_VARIABLE_NAME );
  1464. status = RtlQueryEnvironmentVariable_U(
  1465. ValueData,
  1466. &variableNameString,
  1467. &unicodeString
  1468. );
  1469. if ( !NT_SUCCESS(status) ) {
  1470. shi502->shi502_permissions = 0;
  1471. } else {
  1472. DWORD permissions;
  1473. status = RtlUnicodeStringToInteger(
  1474. &unicodeString,
  1475. 0,
  1476. &permissions
  1477. );
  1478. if ( !NT_SUCCESS(status) ) {
  1479. subStrings[0] = ValueName;
  1480. subStrings[1] = SHARES_REGISTRY_PATH;
  1481. SsLogEvent(
  1482. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1483. 2,
  1484. subStrings,
  1485. RtlNtStatusToDosError( status )
  1486. );
  1487. IF_DEBUG(REGISTRY) {
  1488. SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
  1489. "%lx\n", status ));
  1490. }
  1491. goto errorexit;
  1492. }
  1493. shi502->shi502_permissions = permissions;
  1494. }
  1495. //
  1496. // Get the maximum number of uses allowed. It may be omitted.
  1497. //
  1498. RtlInitUnicodeString( &variableNameString, MAXUSES_VARIABLE_NAME );
  1499. status = RtlQueryEnvironmentVariable_U(
  1500. ValueData,
  1501. &variableNameString,
  1502. &unicodeString
  1503. );
  1504. if ( !NT_SUCCESS(status) ) {
  1505. shi502->shi502_max_uses = (DWORD)SHI_USES_UNLIMITED;
  1506. } else {
  1507. status = RtlUnicodeStringToInteger(
  1508. &unicodeString,
  1509. 0,
  1510. &shi502->shi502_max_uses
  1511. );
  1512. if ( !NT_SUCCESS(status) ) {
  1513. subStrings[0] = ValueName;
  1514. subStrings[1] = SHARES_REGISTRY_PATH;
  1515. SsLogEvent(
  1516. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1517. 2,
  1518. subStrings,
  1519. RtlNtStatusToDosError( status )
  1520. );
  1521. goto errorexit;
  1522. }
  1523. }
  1524. //
  1525. // Get the Cacheing flags. It may be omitted.
  1526. //
  1527. RtlInitUnicodeString( &variableNameString, CSC_VARIABLE_NAME );
  1528. *CacheState = 0;
  1529. status = RtlQueryEnvironmentVariable_U(
  1530. ValueData,
  1531. &variableNameString,
  1532. &unicodeString
  1533. );
  1534. if( NT_SUCCESS( status ) ) {
  1535. ULONG value;
  1536. status = RtlUnicodeStringToInteger(
  1537. &unicodeString,
  1538. 0,
  1539. &value
  1540. );
  1541. if( NT_SUCCESS( status ) ) {
  1542. *CacheState = (value & CSC_MASK);
  1543. } else {
  1544. subStrings[0] = ValueName;
  1545. subStrings[1] = SHARES_REGISTRY_PATH;
  1546. SsLogEvent(
  1547. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1548. 2,
  1549. subStrings,
  1550. RtlNtStatusToDosError( status )
  1551. );
  1552. }
  1553. }
  1554. {
  1555. //
  1556. // Get the Share file security descriptor
  1557. //
  1558. RTL_QUERY_REGISTRY_TABLE shareQueryTable[2];
  1559. //
  1560. // Fill up the query table
  1561. //
  1562. shareQueryTable[0].QueryRoutine = GetSdFromRegistry;
  1563. shareQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  1564. shareQueryTable[0].Name = shi502->shi502_netname;
  1565. shareQueryTable[0].EntryContext = NULL;
  1566. shareQueryTable[0].DefaultType = REG_NONE;
  1567. shareQueryTable[1].QueryRoutine = NULL;
  1568. shareQueryTable[1].Flags = 0;
  1569. shareQueryTable[1].Name = NULL;
  1570. status = RtlQueryRegistryValues(
  1571. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1572. SHARES_SECURITY_REGISTRY_PATH,
  1573. shareQueryTable,
  1574. shi502,
  1575. NULL
  1576. );
  1577. if ( !NT_SUCCESS( status) &&
  1578. ( status != STATUS_OBJECT_NAME_NOT_FOUND ) ) {
  1579. ASSERT(0);
  1580. IF_DEBUG(REGISTRY) {
  1581. SS_PRINT(( "GetStickyShareInfo: Get file SD: "
  1582. "%lx\n", status ));
  1583. }
  1584. goto errorexit;
  1585. }
  1586. }
  1587. return TRUE;
  1588. errorexit:
  1589. if ( RemarkString->Buffer != NULL ) {
  1590. RtlFreeUnicodeString( RemarkString );
  1591. }
  1592. if ( PathString->Buffer != NULL ) {
  1593. RtlFreeUnicodeString( PathString );
  1594. }
  1595. if ( shi502->shi502_security_descriptor != NULL ) {
  1596. MIDL_user_free( shi502->shi502_security_descriptor );
  1597. }
  1598. return FALSE;
  1599. } // GetStickyShareInfo
  1600. BOOLEAN
  1601. SsGetDefaultSdFromRegistry (
  1602. IN PWCH ValueName,
  1603. OUT PSECURITY_DESCRIPTOR *FileSD
  1604. )
  1605. /*++
  1606. Routine Description:
  1607. Reads 'ValueName' from the registry and gets the security descriptor
  1608. stored there.
  1609. Arguments:
  1610. ValueName - The name of the registry value in the Parameters section holding the descriptor
  1611. FileSD - points to the allocated SD if one was obtained
  1612. Return Value:
  1613. NTSTATUS - success/failure of the operation.
  1614. --*/
  1615. {
  1616. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1617. SHARE_INFO_502 shi502 = {0};
  1618. NTSTATUS status;
  1619. *FileSD = NULL;
  1620. queryTable[0].QueryRoutine = GetSdFromRegistry;
  1621. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  1622. queryTable[0].Name = ValueName;
  1623. queryTable[0].EntryContext = NULL;
  1624. queryTable[0].DefaultType = REG_NONE;
  1625. queryTable[1].QueryRoutine = NULL;
  1626. queryTable[1].Flags = 0;
  1627. queryTable[1].Name = NULL;
  1628. status = RtlQueryRegistryValues(
  1629. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1630. SHARES_DEFAULT_SECURITY_REGISTRY_PATH,
  1631. queryTable,
  1632. &shi502,
  1633. NULL
  1634. );
  1635. if ( NT_SUCCESS( status) ) {
  1636. IF_DEBUG(INITIALIZATION) {
  1637. SS_PRINT(( "SsGetDefaultSdFromRegistry: using %ws SD from registry.\n",
  1638. ValueName ));
  1639. }
  1640. *FileSD = shi502.shi502_security_descriptor;
  1641. return TRUE;
  1642. }
  1643. return FALSE;
  1644. }
  1645. VOID
  1646. SsWriteDefaultSdToRegistry (
  1647. IN PWCH ValueName,
  1648. IN PSECURITY_DESCRIPTOR FileSD
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. Stores FileSD to 'ValueName' in the registry
  1653. Arguments:
  1654. ValueName - The name of the registry value in the Parameters section holding the descriptor
  1655. FileSD - points to the SD to write
  1656. --*/
  1657. {
  1658. ULONG fileSDLength;
  1659. if ( RtlValidSecurityDescriptor( FileSD ) ) {
  1660. fileSDLength = RtlLengthSecurityDescriptor( FileSD );
  1661. RtlWriteRegistryValue(
  1662. RTL_REGISTRY_SERVICES,
  1663. SHARES_DEFAULT_SECURITY_REGISTRY_PATH,
  1664. ValueName,
  1665. REG_BINARY,
  1666. (LPBYTE)FileSD,
  1667. fileSDLength
  1668. );
  1669. }
  1670. }
  1671. LONG
  1672. LoadParameters (
  1673. PWCH Path
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. Reads the registry to get server parameters.
  1678. Arguments:
  1679. Path - PARAMETERS_REGISTRY_PATH or AUTOTUNED_REGISTRY_PATH
  1680. Return Value:
  1681. LONG - success/failure of the operation.
  1682. --*/
  1683. {
  1684. NTSTATUS status;
  1685. PRTL_QUERY_REGISTRY_TABLE queryTable;
  1686. ULONG numberOfBindings = 0;
  1687. //
  1688. // Ask the RTL to call us back for each value in the appropriate
  1689. // key.
  1690. //
  1691. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  1692. if ( queryTable != NULL ) {
  1693. queryTable[0].QueryRoutine = SetStickyParameter;
  1694. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  1695. queryTable[0].Name = NULL;
  1696. queryTable[0].EntryContext = NULL;
  1697. queryTable[0].DefaultType = REG_NONE;
  1698. queryTable[0].DefaultData = NULL;
  1699. queryTable[0].DefaultLength = 0;
  1700. queryTable[1].QueryRoutine = NULL;
  1701. queryTable[1].Flags = 0;
  1702. queryTable[1].Name = NULL;
  1703. status = RtlQueryRegistryValues(
  1704. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1705. Path,
  1706. queryTable,
  1707. Path, // Context for SetStickyParameter
  1708. NULL
  1709. );
  1710. MIDL_user_free( queryTable );
  1711. } else {
  1712. status = STATUS_INSUFFICIENT_RESOURCES;
  1713. }
  1714. if ( !NT_SUCCESS(status) ) {
  1715. IF_DEBUG(INITIALIZATION) {
  1716. SS_PRINT(( "LoadParameters: RtlQueryRegistryValues failed: "
  1717. "%lx\n", status ));
  1718. }
  1719. return RtlNtStatusToDosError( status );
  1720. }
  1721. return NO_ERROR;
  1722. } // LoadParameters
  1723. LONG
  1724. LoadSizeParameter (
  1725. VOID
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. Reads the registry to get the basic server Size parameter.
  1730. Arguments:
  1731. None.
  1732. Return Value:
  1733. LONG - success/failure of the operation.
  1734. --*/
  1735. {
  1736. NTSTATUS status;
  1737. PRTL_QUERY_REGISTRY_TABLE queryTable;
  1738. ULONG numberOfBindings = 0;
  1739. //
  1740. // Ask the RTL to call us back if the Size parameter exists.
  1741. //
  1742. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  1743. if ( queryTable != NULL ) {
  1744. queryTable[0].QueryRoutine = SetSizeParameters;
  1745. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  1746. queryTable[0].Name = SIZE_VALUE_NAME;
  1747. queryTable[0].EntryContext = NULL;
  1748. queryTable[0].DefaultType = REG_NONE;
  1749. queryTable[0].DefaultData = NULL;
  1750. queryTable[0].DefaultLength = 0;
  1751. queryTable[1].QueryRoutine = NULL;
  1752. queryTable[1].Flags = 0;
  1753. queryTable[1].Name = NULL;
  1754. status = RtlQueryRegistryValues(
  1755. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1756. PARAMETERS_REGISTRY_PATH,
  1757. queryTable,
  1758. NULL,
  1759. NULL
  1760. );
  1761. MIDL_user_free( queryTable );
  1762. } else {
  1763. status = STATUS_INSUFFICIENT_RESOURCES;
  1764. }
  1765. if ( !NT_SUCCESS(status) ) {
  1766. IF_DEBUG(INITIALIZATION) {
  1767. SS_PRINT(( "LoadSizeParameter: RtlQueryRegistryValues failed: "
  1768. "%lx\n", status ));
  1769. }
  1770. return RtlNtStatusToDosError( status );
  1771. }
  1772. return NO_ERROR;
  1773. } // LoadSizeParameter
  1774. VOID
  1775. PrintShareAnnounce (
  1776. LPVOID event
  1777. )
  1778. {
  1779. ULONG i;
  1780. //
  1781. // Announce ourselves and then wait for awhile.
  1782. // If the event gets signaled, terminate the loop and this thread.
  1783. // But don't do this forever, since the print subsystem may actually
  1784. // get stuck
  1785. //
  1786. //
  1787. // Do it for 15 minutes
  1788. //
  1789. for( i=0; i < 60; i++ ) {
  1790. AnnounceServiceStatus( 1 );
  1791. if( WaitForSingleObject( (HANDLE)event, 15*1000 ) != WAIT_TIMEOUT ) {
  1792. break;
  1793. }
  1794. }
  1795. }
  1796. NTSTATUS
  1797. RecreateStickyShare (
  1798. IN PWSTR ValueName,
  1799. IN ULONG ValueType,
  1800. IN PVOID ValueData,
  1801. IN ULONG ValueLength,
  1802. IN PULONG IterationCount,
  1803. IN PVOID EntryContext
  1804. )
  1805. {
  1806. NET_API_STATUS error;
  1807. SHARE_INFO_502 shi502;
  1808. SHARE_INFO shareInfo;
  1809. UNICODE_STRING pathString;
  1810. UNICODE_STRING remarkString;
  1811. HANDLE threadHandle = NULL;
  1812. HANDLE event = NULL;
  1813. DWORD CacheState;
  1814. SHARE_INFO shareInfoBuffer;
  1815. SHARE_INFO_1005 si1005;
  1816. ValueLength, EntryContext;
  1817. remarkString.Buffer = NULL;
  1818. pathString.Buffer = NULL;
  1819. if ( GetStickyShareInfo(
  1820. ValueName,
  1821. ValueType,
  1822. ValueData,
  1823. &remarkString,
  1824. &pathString,
  1825. &shi502,
  1826. &CacheState
  1827. ) ) {
  1828. //
  1829. // Do the actual add of the share.
  1830. //
  1831. IF_DEBUG(INITIALIZATION) {
  1832. SS_PRINT(( "RecreateStickyShares: adding share %ws\n", ValueName ));
  1833. }
  1834. shi502.shi502_remark = remarkString.Buffer;
  1835. shi502.shi502_path = pathString.Buffer;
  1836. shareInfo.ShareInfo502 = (LPSHARE_INFO_502_I)&shi502;
  1837. if( shi502.shi502_type == STYPE_PRINTQ ) {
  1838. //
  1839. // A really big problem is that FAX printers can take aribitrarily long to
  1840. // complete the eventual OpenPrinter() call which the server will make back
  1841. // up to srvsvc. And if we don't announce ourselves in the interval, the
  1842. // service controller will presume that we got stuck on startup. Since
  1843. // NetrShareAdd() is synchronous, we need to get a different thread to
  1844. // announce our service status until NetrShareAdd returns. So, start it
  1845. // now. This is most unfortunate.
  1846. event = CreateEvent( NULL, TRUE, FALSE, NULL );
  1847. if( event != NULL ) {
  1848. DWORD threadId;
  1849. threadHandle = CreateThread(
  1850. NULL,
  1851. 0,
  1852. (LPTHREAD_START_ROUTINE)PrintShareAnnounce,
  1853. (LPVOID)event,
  1854. 0,
  1855. &threadId
  1856. );
  1857. if( threadHandle == NULL ) {
  1858. CloseHandle( event );
  1859. event = NULL;
  1860. }
  1861. }
  1862. }
  1863. //
  1864. // RecreateStickyShare is called during server initialization. The service
  1865. // controller will presume that we're stuck if we don't update our status
  1866. // with it often enough. So every 64 recreated shares we call back to it.
  1867. // There's nothing magic about the 64 -- easy to check for, and not too often.
  1868. //
  1869. if( (shi502.shi502_type == STYPE_PRINTQ && threadHandle == NULL) ||
  1870. (++(*IterationCount) & 63 ) == 0 ) {
  1871. AnnounceServiceStatus( 1 );
  1872. }
  1873. error = NetrShareAdd( NULL, 502, &shareInfo, NULL );
  1874. if( event != NULL ) {
  1875. //
  1876. // We created an announcement thread, set the event telling it to terminate
  1877. //
  1878. SetEvent( event );
  1879. //
  1880. // Wait for the thread to terminate
  1881. //
  1882. if( WaitForSingleObject( threadHandle, INFINITE ) == WAIT_FAILED ) {
  1883. error = GetLastError();
  1884. }
  1885. //
  1886. // Close the handles
  1887. //
  1888. CloseHandle( event );
  1889. CloseHandle( threadHandle );
  1890. }
  1891. if ( error != NO_ERROR ) {
  1892. IF_DEBUG(INITIALIZATION_ERRORS) {
  1893. SS_PRINT(( "RecreateStickyShares: failed to add share "
  1894. "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
  1895. }
  1896. }
  1897. //
  1898. // If this is a share which can be cached, set the caching flag in the server
  1899. //
  1900. si1005.shi1005_flags = CacheState;
  1901. if( si1005.shi1005_flags ) {
  1902. shareInfoBuffer.ShareInfo1005 = &si1005;
  1903. NetrShareSetInfo( NULL, ValueName, 1005, &shareInfoBuffer, NULL );
  1904. }
  1905. //
  1906. // free buffers allocated by GetStickyShareInfo
  1907. //
  1908. if ( remarkString.Buffer != NULL ) {
  1909. RtlFreeUnicodeString( &remarkString );
  1910. }
  1911. if ( pathString.Buffer != NULL ) {
  1912. RtlFreeUnicodeString( &pathString );
  1913. }
  1914. if ( shi502.shi502_security_descriptor != NULL ) {
  1915. MIDL_user_free( shi502.shi502_security_descriptor );
  1916. }
  1917. }
  1918. return NO_ERROR;
  1919. } // RecreateStickyShare
  1920. NTSTATUS
  1921. SaveSdToRegistry(
  1922. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1923. IN PWSTR ShareName
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. Stores the share file security descriptor in the registry.
  1928. Arguments:
  1929. SecurityDescriptor - Points to a self-relative security descriptor
  1930. describing the access rights for files under this share.
  1931. ShareName - Points to a string containing the share name under
  1932. which the SD is to be stored.
  1933. Return Value:
  1934. Status of the operation.
  1935. --*/
  1936. {
  1937. NTSTATUS status;
  1938. //
  1939. // Store the security descriptor
  1940. //
  1941. ULONG fileSDLength;
  1942. if ( !RtlValidSecurityDescriptor( SecurityDescriptor ) ) {
  1943. status = STATUS_INVALID_SECURITY_DESCR;
  1944. } else {
  1945. fileSDLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  1946. status = RtlWriteRegistryValue(
  1947. RTL_REGISTRY_SERVICES,
  1948. SHARES_SECURITY_REGISTRY_PATH,
  1949. ShareName,
  1950. REG_BINARY,
  1951. (LPBYTE)SecurityDescriptor,
  1952. fileSDLength
  1953. );
  1954. }
  1955. return status;
  1956. } // SaveSdToRegistry
  1957. NTSTATUS
  1958. SetSizeParameters (
  1959. IN PWSTR ValueName,
  1960. IN ULONG ValueType,
  1961. IN PVOID ValueData,
  1962. IN ULONG ValueLength,
  1963. IN PVOID Context,
  1964. IN PVOID EntryContext
  1965. )
  1966. {
  1967. NT_PRODUCT_TYPE productType;
  1968. DWORD size;
  1969. LPWSTR subStrings[2];
  1970. ValueLength, Context, EntryContext;
  1971. //
  1972. // Get the product type.
  1973. //
  1974. if ( !RtlGetNtProductType( &productType ) ) {
  1975. productType = NtProductWinNt;
  1976. }
  1977. SsData.ServerInfo598.sv598_producttype = productType;
  1978. //
  1979. // Make sure that we got called for the right value.
  1980. //
  1981. ASSERT( _wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0 );
  1982. //
  1983. // The Size value must be a DWORD, and must be in the following
  1984. // range:
  1985. //
  1986. // 0 -> use defaults
  1987. // 1 -> small server (minimize memory usage)
  1988. // 2 -> medium server (balance)
  1989. // 3 -> large server (maximize connections)
  1990. //
  1991. if ( ValueType == REG_DWORD ) {
  1992. ASSERT( ValueLength == sizeof(DWORD) );
  1993. size = *(LPDWORD)ValueData;
  1994. }
  1995. if ( (ValueType != REG_DWORD) || (size > 3) ) {
  1996. subStrings[0] = ValueName;
  1997. subStrings[1] = PARAMETERS_REGISTRY_PATH;
  1998. SsLogEvent(
  1999. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2000. 2,
  2001. subStrings,
  2002. NO_ERROR
  2003. );
  2004. IF_DEBUG(REGISTRY) {
  2005. SS_PRINT(( "SetSizeParameters: skipping invalid value "
  2006. "%ws\n", ValueName ));
  2007. }
  2008. return STATUS_SUCCESS;
  2009. }
  2010. SsData.ServerInfo598.sv598_serversize = size;
  2011. //
  2012. // Set appropriate fields based on the product type (Windows NT or
  2013. // Advanced Server) and the selected Size. Note that a Size of 0
  2014. // doesn't change any of the defaults.
  2015. //
  2016. // Note that the user limit is always -1 (unlimited). Autodisconnect
  2017. // always defaults to 15 minutes.
  2018. //
  2019. if ( size != 0 ) {
  2020. SYSTEM_BASIC_INFORMATION basicInfo;
  2021. NTSTATUS status;
  2022. ULONG noOfMb;
  2023. ULONG factor;
  2024. ULONG asFactor;
  2025. //
  2026. // Get system memory size.
  2027. //
  2028. status = NtQuerySystemInformation(
  2029. SystemBasicInformation,
  2030. &basicInfo,
  2031. sizeof( SYSTEM_BASIC_INFORMATION ),
  2032. NULL
  2033. );
  2034. if ( status != STATUS_SUCCESS ) {
  2035. subStrings[0] = ValueName;
  2036. subStrings[1] = PARAMETERS_REGISTRY_PATH;
  2037. SsLogEvent(
  2038. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2039. 2,
  2040. subStrings,
  2041. NO_ERROR
  2042. );
  2043. IF_DEBUG(REGISTRY) {
  2044. SS_PRINT(( "SetSizeParameters: NtQuerySystemInfo failed %x\n",
  2045. status ));
  2046. }
  2047. return STATUS_SUCCESS;
  2048. }
  2049. //
  2050. // Note that we first divide the page size by 512 in order to
  2051. // allow for physical memory sizes above 2^32-1. With this
  2052. // calculation, we can handle up to two terabytes of physical
  2053. // memory. The calculation assumes that the page size is at
  2054. // least 512, and is not very accurate if the page size is not
  2055. // a power of 2 (very unlikely).
  2056. //
  2057. ASSERT( basicInfo.PageSize >= 512 );
  2058. noOfMb = (((basicInfo.PageSize / 512) *
  2059. basicInfo.NumberOfPhysicalPages) +
  2060. (1 MB / 512 - 1)) / (1 MB / 512);
  2061. //
  2062. // Minimum is 8 MB
  2063. //
  2064. noOfMb = MAX( MIN_SYSTEM_SIZE, noOfMb );
  2065. //
  2066. // If we have NTAS, and we're set to maximize performance or we have
  2067. // lots of memory -- then set the default work item buffer size to
  2068. // a larger value. This value has been chosen to work well with our
  2069. // implementation of TCP/IP, and shows itself to advantage when doing
  2070. // directory emumerations with directories having lots of entries in them.
  2071. //
  2072. if( productType != NtProductWinNt && ((noOfMb >= 512) && (size == 3)) ) {
  2073. SsData.ServerInfo599.sv599_sizreqbuf = DEF_LARGE_SIZREQBUF;
  2074. }
  2075. //
  2076. // Set the maximum for the different sizes
  2077. //
  2078. if ( size == 1 ) {
  2079. noOfMb = MIN( noOfMb, MAX_SMALL_SIZE );
  2080. } else if ( size == 2 ) {
  2081. noOfMb = MIN( noOfMb, MAX_MEDIUM_SIZE );
  2082. }
  2083. //
  2084. // If small, assume the system size is half of the real one.
  2085. // This should give us half the paramater values of a medium server.
  2086. // If large, double it. Also set the free connection count.
  2087. //
  2088. if ( size == 1 ) {
  2089. //
  2090. // Small
  2091. //
  2092. factor = (noOfMb + 1) / 2;
  2093. SsData.ServerInfo599.sv599_minfreeconnections = 2;
  2094. SsData.ServerInfo599.sv599_maxfreeconnections = 2;
  2095. } else if ( size == 2 ) {
  2096. //
  2097. // Balanced
  2098. //
  2099. factor = noOfMb;
  2100. SsData.ServerInfo599.sv599_minfreeconnections = 2;
  2101. SsData.ServerInfo599.sv599_maxfreeconnections = 4;
  2102. } else {
  2103. //
  2104. // Large
  2105. //
  2106. factor = noOfMb * 2;
  2107. // Scale up our big servers, this uses the NEW version of small/med/large we picked
  2108. // for the server service (< 1 GB, 1-16 GB, >16 GB)
  2109. if( noOfMb < 1024 )
  2110. {
  2111. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_SMALL;
  2112. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_SMALL;
  2113. }
  2114. else if( noOfMb < 16*1024 )
  2115. {
  2116. // >= 1 GB memory
  2117. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_MEDIUM;
  2118. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_MEDIUM;
  2119. }
  2120. else {
  2121. // >= 16 GB memory
  2122. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_LARGE;
  2123. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_LARGE;
  2124. }
  2125. }
  2126. //
  2127. // If this is an Advanced Server with at least 24M, some
  2128. // parameter will need to be even bigger.
  2129. //
  2130. asFactor = 1;
  2131. if ( (productType != NtProductWinNt) && (noOfMb >= 24) ) asFactor = 2;
  2132. //
  2133. // Now set the values for a medium server with this much memory.
  2134. //
  2135. SsData.ServerInfo599.sv599_maxworkitems =
  2136. MedSrvCfgTbl.maxworkitems[0] * factor * asFactor /
  2137. MedSrvCfgTbl.maxworkitems[1];
  2138. SsData.ServerInfo599.sv599_initworkitems =
  2139. MedSrvCfgTbl.initworkitems[0] * factor * asFactor /
  2140. MedSrvCfgTbl.initworkitems[1];
  2141. SsData.ServerInfo599.sv599_rawworkitems =
  2142. MedSrvCfgTbl.rawworkitems[0] * factor /
  2143. MedSrvCfgTbl.rawworkitems[1];
  2144. SsData.ServerInfo598.sv598_maxrawworkitems =
  2145. MedSrvCfgTbl.maxrawworkitems[0] * factor * asFactor /
  2146. MedSrvCfgTbl.maxrawworkitems[1];
  2147. SsData.ServerInfo599.sv599_maxworkitems =
  2148. MIN( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS );
  2149. SsData.ServerInfo599.sv599_initworkitems =
  2150. MIN( SsData.ServerInfo599.sv599_initworkitems, MAX_INITWORKITEMS/4 );
  2151. SsData.ServerInfo599.sv599_rawworkitems =
  2152. MIN( SsData.ServerInfo599.sv599_rawworkitems, MAX_RAWWORKITEMS/4 );
  2153. SsData.ServerInfo598.sv598_maxrawworkitems =
  2154. MIN( SsData.ServerInfo598.sv598_maxrawworkitems, MAX_MAXRAWWORKITEMS );
  2155. if ( (productType != NtProductWinNt) || (size == 3) ) {
  2156. SsData.ServerInfo599.sv599_maxpagedmemoryusage = INF;
  2157. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage = INF;
  2158. } else {
  2159. SsData.ServerInfo599.sv599_maxpagedmemoryusage =
  2160. MedSrvCfgTbl.maxpagedmemoryusage[0] * factor /
  2161. MedSrvCfgTbl.maxpagedmemoryusage[1] MB;
  2162. SsData.ServerInfo599.sv599_maxpagedmemoryusage =
  2163. MAX( SsData.ServerInfo599.sv599_maxpagedmemoryusage,
  2164. MIN_MAXPAGEDMEMORYUSAGE);
  2165. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
  2166. MedSrvCfgTbl.maxnonpagedmemoryusage[0] * factor /
  2167. MedSrvCfgTbl.maxnonpagedmemoryusage[1] MB;
  2168. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
  2169. MAX( SsData.ServerInfo599.sv599_maxnonpagedmemoryusage,
  2170. MIN_MAXNONPAGEDMEMORYUSAGE);
  2171. }
  2172. }
  2173. return STATUS_SUCCESS;
  2174. } // SetSizeParameters
  2175. NTSTATUS
  2176. SetStickyParameter (
  2177. IN PWSTR ValueName,
  2178. IN ULONG ValueType,
  2179. IN PVOID ValueData,
  2180. IN ULONG ValueLength,
  2181. IN PVOID Context,
  2182. IN PVOID EntryContext
  2183. )
  2184. {
  2185. NET_API_STATUS error;
  2186. DWORD_PTR i;
  2187. PFIELD_DESCRIPTOR foundField = NULL;
  2188. LPWSTR subStrings[2];
  2189. ValueLength, EntryContext;
  2190. //
  2191. // Ignore several parameters, since they are handled elsewhere
  2192. //
  2193. if( (_wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0) ||
  2194. (_wcsicmp( ValueName, NULL_SESSION_SHARES_VALUE_NAME ) == 0) ||
  2195. (_wcsicmp( ValueName, NULL_SESSION_PIPES_VALUE_NAME ) == 0) ||
  2196. (_wcsicmp( ValueName, PIPES_NEED_LICENSE_VALUE_NAME ) == 0) ||
  2197. (_wcsicmp( ValueName, ERROR_LOG_IGNORE_VALUE_NAME ) == 0) ||
  2198. (_wcsicmp( ValueName, GUID_VARIABLE_NAME ) == 0) ||
  2199. (_wcsicmp( ValueName, OPTIONAL_NAMES_VALUE_NAME ) == 0) ||
  2200. (_wcsicmp( ValueName, NO_REMAP_PIPES_VALUE_NAME ) == 0) ||
  2201. (_wcsicmp( ValueName, SERVICE_DLL_VALUE_NAME ) == 0) ) {
  2202. return STATUS_SUCCESS;
  2203. }
  2204. //
  2205. // Determine which field we need to set, based on the value
  2206. // name.
  2207. //
  2208. // NOTE: For Daytona, disc and comment are now invalid registry names.
  2209. // We use their more famous aliases autodisconnect and srvcomment
  2210. // instead. If we get more of these cases, we should consider adding
  2211. // a field to the FIELD_DESCRIPTOR structure that indicates whether
  2212. // the names are should appear on the registry or not. Any change
  2213. // here should also be made to SsSetField().
  2214. //
  2215. if ( (_wcsicmp( ValueName, DISC_VALUE_NAME ) != 0) &&
  2216. (_wcsicmp( ValueName, COMMENT_VALUE_NAME ) != 0) ) {
  2217. for ( i = 0;
  2218. SsServerInfoFields[i].FieldName != NULL;
  2219. i++ ) {
  2220. if ( _wcsicmp( ValueName, SsServerInfoFields[i].FieldName ) == 0 ) {
  2221. foundField = &SsServerInfoFields[i];
  2222. break;
  2223. }
  2224. }
  2225. }
  2226. if ( foundField == NULL || foundField->Settable == NOT_SETTABLE ) {
  2227. #ifdef DBG
  2228. subStrings[0] = ValueName;
  2229. subStrings[1] = Context;
  2230. SsLogEvent(
  2231. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2232. 2,
  2233. subStrings,
  2234. NO_ERROR
  2235. );
  2236. IF_DEBUG(REGISTRY) {
  2237. SS_PRINT(( "SetStickyParameter: ignoring %s \"%ws\"\n",
  2238. (foundField == NULL ? "unknown value name" :
  2239. "unsettable value"), ValueName ));
  2240. }
  2241. #endif
  2242. return STATUS_SUCCESS;
  2243. }
  2244. switch ( foundField->FieldType ) {
  2245. case BOOLEAN_FIELD:
  2246. case DWORD_FIELD:
  2247. if ( ValueType != REG_DWORD ) {
  2248. subStrings[0] = ValueName;
  2249. subStrings[1] = Context;
  2250. SsLogEvent(
  2251. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2252. 2,
  2253. subStrings,
  2254. NO_ERROR
  2255. );
  2256. IF_DEBUG(REGISTRY) {
  2257. SS_PRINT(( "SetStickyParameter: skipping invalid value "
  2258. "%ws\n", ValueName ));
  2259. }
  2260. return STATUS_SUCCESS;
  2261. }
  2262. i = *(LPDWORD)ValueData;
  2263. break;
  2264. case LPSTR_FIELD:
  2265. if ( ValueType != REG_SZ ) {
  2266. subStrings[0] = ValueName;
  2267. subStrings[1] = Context;
  2268. SsLogEvent(
  2269. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2270. 2,
  2271. subStrings,
  2272. NO_ERROR
  2273. );
  2274. IF_DEBUG(REGISTRY) {
  2275. SS_PRINT(( "SetStickyParameter: skipping invalid value "
  2276. "%ws\n", ValueName ));
  2277. }
  2278. return STATUS_SUCCESS;
  2279. }
  2280. if (ValueLength != 0) {
  2281. i = (DWORD_PTR)ValueData;
  2282. } else {
  2283. i = (DWORD_PTR)NULL;
  2284. }
  2285. break;
  2286. }
  2287. //
  2288. // Set the field.
  2289. //
  2290. error = SsSetField( foundField, &i, FALSE, NULL );
  2291. #ifdef DBG
  2292. if ( error != NO_ERROR ) {
  2293. subStrings[0] = ValueName;
  2294. subStrings[1] = Context;
  2295. SsLogEvent(
  2296. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2297. 2,
  2298. subStrings,
  2299. error
  2300. );
  2301. IF_DEBUG(REGISTRY) {
  2302. SS_PRINT(( "SetStickyParameter: error %ld ignored in setting "
  2303. "parameter \"%ws\"n", error, ValueName ));
  2304. }
  2305. }
  2306. #endif
  2307. return STATUS_SUCCESS;
  2308. } // SetStickyParameter