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

3027 lines
80 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. // Check if we need to disable strict name checking because the NetBIOS and DNS names are not the same
  868. // We also want to do this for the cluster name if its present
  869. if( !SsData.ServerInfo598.sv598_disablestrictnamechecking )
  870. {
  871. WCHAR NetbiosName[MAX_COMPUTERNAME_LENGTH + 1];
  872. WCHAR DnsName[MAX_COMPUTERNAME_LENGTH + 1];
  873. DWORD NetbiosNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  874. DWORD DnsNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  875. if( GetComputerNameEx( ComputerNameNetBIOS, NetbiosName, &NetbiosNameLength ) )
  876. {
  877. if( !GetComputerNameEx( ComputerNameDnsHostname, DnsName, &DnsNameLength ) ||
  878. (NetbiosNameLength != DnsNameLength) ||
  879. _wcsnicmp( NetbiosName, DnsName, MAX_COMPUTERNAME_LENGTH + 1 ) )
  880. {
  881. SsData.ServerInfo598.sv598_disablestrictnamechecking = TRUE;
  882. }
  883. else
  884. {
  885. NetbiosNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  886. DnsNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  887. if( GetComputerNameEx( ComputerNamePhysicalNetBIOS, NetbiosName, &NetbiosNameLength ) )
  888. {
  889. if( !GetComputerNameEx( ComputerNamePhysicalDnsHostname, DnsName, &DnsNameLength ) ||
  890. (NetbiosNameLength != DnsNameLength) ||
  891. _wcsnicmp( NetbiosName, DnsName, MAX_COMPUTERNAME_LENGTH + 1 ) )
  892. {
  893. SsData.ServerInfo598.sv598_disablestrictnamechecking = TRUE;
  894. }
  895. }
  896. }
  897. }
  898. }
  899. return error;
  900. } // SsLoadConfigurationParameters
  901. NET_API_STATUS
  902. SsRecreateStickyShares (
  903. VOID
  904. )
  905. /*++
  906. Routine Description:
  907. Reads the registry to find and create sticky shares.
  908. Arguments:
  909. None.
  910. Return Value:
  911. NET_API_STATUS - success/failure of the operation.
  912. --*/
  913. {
  914. NTSTATUS status;
  915. PRTL_QUERY_REGISTRY_TABLE queryTable;
  916. ULONG IterationCount = 0;
  917. //
  918. // Ask the RTL to call us back for each value in the Shares key.
  919. //
  920. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  921. if ( queryTable != NULL ) {
  922. queryTable[0].QueryRoutine = RecreateStickyShare;
  923. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  924. queryTable[0].Name = NULL;
  925. queryTable[0].EntryContext = NULL;
  926. queryTable[0].DefaultType = REG_NONE;
  927. queryTable[0].DefaultData = NULL;
  928. queryTable[0].DefaultLength = 0;
  929. queryTable[1].QueryRoutine = NULL;
  930. queryTable[1].Flags = 0;
  931. queryTable[1].Name = NULL;
  932. status = RtlQueryRegistryValues(
  933. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  934. SHARES_REGISTRY_PATH,
  935. queryTable,
  936. &IterationCount,
  937. NULL
  938. );
  939. MIDL_user_free( queryTable );
  940. } else {
  941. status = STATUS_INSUFFICIENT_RESOURCES;
  942. }
  943. if ( !NT_SUCCESS(status) ) {
  944. IF_DEBUG(INITIALIZATION) {
  945. SS_PRINT(( "SsRecreateStickyShares: RtlQueryRegistryValues "
  946. "failed: %lx\n", status ));
  947. }
  948. return RtlNtStatusToDosError( status );
  949. }
  950. return NO_ERROR;
  951. } // SsRecreateStickyShares
  952. NET_API_STATUS
  953. SsRemoveShareFromRegistry (
  954. LPWSTR NetName
  955. )
  956. {
  957. NET_API_STATUS error = NO_ERROR;
  958. NTSTATUS status;
  959. PWCH valueName;
  960. //
  961. // The value name is the share name. Remove that value from the
  962. // Shares key.
  963. //
  964. valueName = NetName;
  965. //
  966. // Delete the share security
  967. //
  968. status = RtlDeleteRegistryValue(
  969. RTL_REGISTRY_SERVICES,
  970. SHARES_SECURITY_REGISTRY_PATH,
  971. valueName
  972. );
  973. if ( !NT_SUCCESS(status) ) {
  974. IF_DEBUG(REGISTRY) {
  975. SS_PRINT(( "SsRemoveShareFromRegistry: Delete Security value failed: %lx; "
  976. "share %ws will return\n", status, valueName ));
  977. }
  978. }
  979. //
  980. // Delete the share
  981. //
  982. status = RtlDeleteRegistryValue(
  983. RTL_REGISTRY_SERVICES,
  984. SHARES_REGISTRY_PATH,
  985. valueName
  986. );
  987. if ( !NT_SUCCESS(status) ) {
  988. IF_DEBUG(REGISTRY) {
  989. SS_PRINT(( "SsRemoveShareFromRegistry: DeleteValue failed: %lx; "
  990. "share %ws will return\n", status, valueName ));
  991. }
  992. error = RtlNtStatusToDosError( status );
  993. }
  994. return error;
  995. } // SsRemoveShareFromRegistry
  996. VOID
  997. BindToTransport (
  998. IN LPWSTR TransportName
  999. )
  1000. {
  1001. NET_API_STATUS error;
  1002. SERVER_TRANSPORT_INFO_0 svti0;
  1003. RtlZeroMemory( &svti0, sizeof( svti0 ) );
  1004. svti0.svti0_transportname = TransportName;
  1005. svti0.svti0_transportaddress = SsData.SsServerTransportAddress;
  1006. svti0.svti0_transportaddresslength =
  1007. ComputeTransportAddressClippedLength(
  1008. SsData.SsServerTransportAddress,
  1009. SsData.SsServerTransportAddressLength );
  1010. //
  1011. // Bind to the transport.
  1012. //
  1013. IF_DEBUG(INITIALIZATION) {
  1014. SS_PRINT(( "BindToTransport: binding to transport %ws\n", TransportName ));
  1015. }
  1016. error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&svti0 );
  1017. if ( error != NO_ERROR ) {
  1018. DWORD eventId;
  1019. LPWSTR subStrings[2];
  1020. IF_DEBUG(INITIALIZATION_ERRORS) {
  1021. SS_PRINT(( "SsBindToTransports: failed to bind to %ws: "
  1022. "%ld\n", TransportName, error ));
  1023. }
  1024. eventId = (error == ERROR_DUP_NAME || error == ERROR_INVALID_NETNAME ) ?
  1025. EVENT_SRV_CANT_BIND_DUP_NAME :
  1026. EVENT_SRV_CANT_BIND_TO_TRANSPORT;
  1027. subStrings[0] = TransportName;
  1028. SsLogEvent(
  1029. eventId,
  1030. 1,
  1031. subStrings,
  1032. error
  1033. );
  1034. }
  1035. } // BindToTransport
  1036. NTSTATUS
  1037. BindOptionalNameToTransport (
  1038. IN PWSTR ValueName,
  1039. IN ULONG ValueType,
  1040. IN PVOID ValueData,
  1041. IN ULONG ValueLength,
  1042. IN PVOID Context,
  1043. IN PVOID EntryContext
  1044. )
  1045. {
  1046. SERVER_TRANSPORT_INFO_0 sti;
  1047. UCHAR serverName[ MAX_PATH ];
  1048. UNICODE_STRING UnicodeName;
  1049. NET_API_STATUS error;
  1050. LPWSTR subStrings[2];
  1051. ULONG namelen;
  1052. subStrings[0] = (LPWSTR)ValueData;
  1053. subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
  1054. if( ValueType != REG_SZ ) {
  1055. //
  1056. // Not a string!
  1057. //
  1058. SsLogEvent(
  1059. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1060. 2,
  1061. subStrings,
  1062. NO_ERROR
  1063. );
  1064. return STATUS_SUCCESS;
  1065. }
  1066. UnicodeName.Length = wcslen( (LPWSTR)ValueData ) * sizeof( WCHAR );
  1067. UnicodeName.MaximumLength = UnicodeName.Length + sizeof( WCHAR );
  1068. UnicodeName.Buffer = (LPWSTR)ValueData;
  1069. error = ConvertStringToTransportAddress( &UnicodeName, serverName, &namelen );
  1070. if( error != NO_ERROR ) {
  1071. //
  1072. // Invalid server name!
  1073. //
  1074. SsLogEvent(
  1075. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1076. 2,
  1077. subStrings,
  1078. error
  1079. );
  1080. return STATUS_SUCCESS;
  1081. }
  1082. RtlZeroMemory( &sti, sizeof(sti) );
  1083. sti.svti0_transportname = (LPWSTR)Context;
  1084. sti.svti0_transportaddress = serverName;
  1085. sti.svti0_transportaddresslength = namelen;
  1086. error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&sti );
  1087. if ( error != NO_ERROR ) {
  1088. //
  1089. // Could not register the name!
  1090. //
  1091. subStrings[0] = (LPWSTR)ValueData;
  1092. subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
  1093. SsLogEvent(
  1094. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1095. 2,
  1096. subStrings,
  1097. error
  1098. );
  1099. }
  1100. return STATUS_SUCCESS;
  1101. }
  1102. VOID
  1103. BindOptionalNames (
  1104. IN PWSTR TransportName
  1105. )
  1106. {
  1107. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1108. NTSTATUS status;
  1109. //
  1110. // We need to iterate over the optional names and bind them to this
  1111. // transport.
  1112. //
  1113. //
  1114. // Now see if there any optional bindings we should perform
  1115. //
  1116. queryTable[0].QueryRoutine = BindOptionalNameToTransport;
  1117. queryTable[0].Flags = 0;
  1118. queryTable[0].Name = OPTIONAL_NAMES_VALUE_NAME;
  1119. queryTable[0].EntryContext = NULL;
  1120. queryTable[0].DefaultType = REG_NONE;
  1121. queryTable[0].DefaultData = NULL;
  1122. queryTable[0].DefaultLength = 0;
  1123. queryTable[1].QueryRoutine = NULL;
  1124. queryTable[1].Flags = 0;
  1125. queryTable[1].Name = NULL;
  1126. (void)RtlQueryRegistryValues(
  1127. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1128. PARAMETERS_REGISTRY_PATH,
  1129. queryTable,
  1130. TransportName,
  1131. NULL
  1132. );
  1133. } // BindOptionalNames
  1134. NTSTATUS
  1135. EnumerateStickyShare (
  1136. IN PWSTR ValueName,
  1137. IN ULONG ValueType,
  1138. IN PVOID ValueData,
  1139. IN ULONG ValueLength,
  1140. IN PVOID Context,
  1141. IN PVOID EntryContext
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. Callback routine for SsEnumerateStickyShare. Routine will get information
  1146. on share and fill in the output buffer.
  1147. Arguments:
  1148. ValueName - Name of the share
  1149. ValueType - Value type of the share name.
  1150. ValueData - Data associated with the ValueName.
  1151. Context - Pointer to our enum information structure.
  1152. Return Value:
  1153. NET_API_STATUS - success/failure of the operation.
  1154. --*/
  1155. {
  1156. NET_API_STATUS error;
  1157. SHARE_INFO_502 shi502;
  1158. UNICODE_STRING pathString;
  1159. UNICODE_STRING remarkString;
  1160. PSRVSVC_SHARE_ENUM_INFO enumInfo = (PSRVSVC_SHARE_ENUM_INFO) Context;
  1161. DWORD cacheState;
  1162. ValueLength, EntryContext;
  1163. remarkString.Buffer = NULL;
  1164. pathString.Buffer = NULL;
  1165. if ( GetStickyShareInfo(
  1166. ValueName,
  1167. ValueType,
  1168. ValueData,
  1169. &remarkString,
  1170. &pathString,
  1171. &shi502,
  1172. &cacheState
  1173. ) ) {
  1174. //
  1175. // Do the actual add of the share.
  1176. //
  1177. IF_DEBUG(REGISTRY) {
  1178. SS_PRINT(( "EnumerateStickyShares: adding share %ws\n", ValueName ));
  1179. }
  1180. shi502.shi502_remark = remarkString.Buffer;
  1181. shi502.shi502_path = pathString.Buffer;
  1182. //
  1183. // Skip until we have the right share to resume from
  1184. //
  1185. if ( (enumInfo->TotalEntries == 0) &&
  1186. (enumInfo->ShareEnumIndex < enumInfo->ResumeHandle) ) {
  1187. enumInfo->ShareEnumIndex++;
  1188. } else {
  1189. enumInfo->TotalEntries++;
  1190. error = FillStickyShareInfo( enumInfo, &shi502 );
  1191. if ( error != NO_ERROR ) {
  1192. IF_DEBUG(REGISTRY) {
  1193. SS_PRINT(( "EnumerateStickyShares: failed to add share "
  1194. "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
  1195. }
  1196. } else {
  1197. enumInfo->EntriesRead++;
  1198. enumInfo->ResumeHandle++;
  1199. }
  1200. }
  1201. //
  1202. // free buffers allocated by GetStickyShareInfo
  1203. //
  1204. if ( remarkString.Buffer != NULL ) {
  1205. RtlFreeUnicodeString( &remarkString );
  1206. }
  1207. if ( pathString.Buffer != NULL ) {
  1208. RtlFreeUnicodeString( &pathString );
  1209. }
  1210. if ( shi502.shi502_security_descriptor != NULL ) {
  1211. MIDL_user_free( shi502.shi502_security_descriptor );
  1212. }
  1213. }
  1214. return STATUS_SUCCESS;
  1215. } // EnumerateStickyShare
  1216. NTSTATUS
  1217. GetSdFromRegistry(
  1218. IN PWSTR ValueName,
  1219. IN ULONG ValueType,
  1220. IN PVOID ValueData,
  1221. IN ULONG ValueLength,
  1222. IN PVOID Context,
  1223. IN PVOID EntryContext
  1224. )
  1225. {
  1226. NTSTATUS status = STATUS_SUCCESS;
  1227. PSECURITY_DESCRIPTOR fileSD = NULL;
  1228. PSHARE_INFO_502 shi502 = (PSHARE_INFO_502) Context;
  1229. LPWSTR subStrings[1];
  1230. EntryContext, ValueName, ValueType;
  1231. if ( ValueLength > 0 ) {
  1232. fileSD = MIDL_user_allocate( ValueLength );
  1233. if ( fileSD == NULL) {
  1234. status = STATUS_INSUFFICIENT_RESOURCES;
  1235. } else {
  1236. RtlCopyMemory(
  1237. fileSD,
  1238. ValueData,
  1239. ValueLength
  1240. );
  1241. if ( !RtlValidSecurityDescriptor( fileSD ) ) {
  1242. subStrings[0] = ValueName;
  1243. SsLogEvent(
  1244. EVENT_SRV_INVALID_SD,
  1245. 1,
  1246. subStrings,
  1247. RtlNtStatusToDosError( status )
  1248. );
  1249. MIDL_user_free( fileSD );
  1250. fileSD = NULL;
  1251. status = STATUS_INVALID_SECURITY_DESCR;
  1252. }
  1253. }
  1254. }
  1255. shi502->shi502_security_descriptor = fileSD;
  1256. return(status);
  1257. } // GetSdFromRegistry
  1258. BOOLEAN
  1259. GetStickyShareInfo (
  1260. IN PWSTR ValueName,
  1261. IN ULONG ValueType,
  1262. IN PVOID ValueData,
  1263. OUT PUNICODE_STRING RemarkString,
  1264. OUT PUNICODE_STRING PathString,
  1265. OUT PSHARE_INFO_502 shi502,
  1266. OUT PDWORD CacheState
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. Gets share information from the registry.
  1271. Arguments:
  1272. ValueName - Name of the share
  1273. ValueType - Value type of the share name.
  1274. ValueData - Data associated with the ValueName.
  1275. RemarkString - Upon return, points to a unicode string containing the
  1276. user remark for this share.
  1277. PathString - Upon return, points to a unicode string containing the
  1278. path for this share.
  1279. shi502 - Upon return, points to a unicode string containing a
  1280. SHARE_INFO_502 structure.
  1281. Return Value:
  1282. TRUE, if share information successfully retrieved.
  1283. FALSE, otherwise.
  1284. --*/
  1285. {
  1286. NTSTATUS status;
  1287. UNICODE_STRING variableNameString;
  1288. WCHAR integerStringBuffer[35];
  1289. UNICODE_STRING unicodeString;
  1290. LPWSTR subStrings[2];
  1291. PathString->Buffer = NULL;
  1292. RemarkString->Buffer = NULL;
  1293. shi502->shi502_security_descriptor = NULL;
  1294. shi502->shi502_path = NULL;
  1295. shi502->shi502_remark = NULL;
  1296. shi502->shi502_reserved = 0;
  1297. //
  1298. // Because the NT server doesn't support share-level security, the
  1299. // password is always NULL.
  1300. //
  1301. shi502->shi502_passwd = NULL;
  1302. //
  1303. // The value type must be REG_MULTI_SZ, and the value name must not
  1304. // be null.
  1305. //
  1306. if ( (ValueType != REG_MULTI_SZ) ||
  1307. (wcslen(ValueName) == 0) ) {
  1308. subStrings[0] = ValueName;
  1309. subStrings[1] = SHARES_REGISTRY_PATH;
  1310. SsLogEvent(
  1311. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1312. 2,
  1313. subStrings,
  1314. NO_ERROR
  1315. );
  1316. IF_DEBUG(REGISTRY) {
  1317. SS_PRINT(( "GetStickyShareInfo: skipping invalid value %ws\n",
  1318. ValueName ));
  1319. }
  1320. goto errorexit;
  1321. }
  1322. //
  1323. // The share name is the value name. The value data describes the
  1324. // rest of the information about the share.
  1325. //
  1326. shi502->shi502_netname = ValueName;
  1327. //
  1328. // The REG_MULTI_SZ format is the same as that used for storing
  1329. // environment variables. Find known share parameters in the data.
  1330. //
  1331. // Get the share path. It must be present.
  1332. //
  1333. RtlInitUnicodeString( &variableNameString, PATH_VARIABLE_NAME );
  1334. PathString->MaximumLength = 0;
  1335. status = RtlQueryEnvironmentVariable_U(
  1336. ValueData,
  1337. &variableNameString,
  1338. PathString
  1339. );
  1340. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1341. //
  1342. // The path is not specified. Ignore this share.
  1343. //
  1344. subStrings[0] = ValueName;
  1345. subStrings[1] = SHARES_REGISTRY_PATH;
  1346. SsLogEvent(
  1347. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1348. 2,
  1349. subStrings,
  1350. RtlNtStatusToDosError( status )
  1351. );
  1352. IF_DEBUG(REGISTRY) {
  1353. SS_PRINT(( "GetStickyShareInfo: No path; ignoring share.\n" ));
  1354. }
  1355. goto errorexit;
  1356. }
  1357. PathString->MaximumLength = (USHORT)(PathString->Length + sizeof(WCHAR));
  1358. PathString->Buffer = MIDL_user_allocate( PathString->MaximumLength );
  1359. if ( PathString->Buffer == NULL ) {
  1360. //
  1361. // No space for path. Ignore this share.
  1362. //
  1363. subStrings[0] = ValueName;
  1364. subStrings[1] = SHARES_REGISTRY_PATH;
  1365. SsLogEvent(
  1366. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1367. 2,
  1368. subStrings,
  1369. ERROR_NOT_ENOUGH_MEMORY
  1370. );
  1371. IF_DEBUG(REGISTRY) {
  1372. SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
  1373. "share.\n" ));
  1374. }
  1375. goto errorexit;
  1376. }
  1377. status = RtlQueryEnvironmentVariable_U(
  1378. ValueData,
  1379. &variableNameString,
  1380. PathString
  1381. );
  1382. if ( !NT_SUCCESS(status) ) {
  1383. //
  1384. // Huh? The second attempt failed. Ignore this share.
  1385. //
  1386. subStrings[0] = ValueName;
  1387. subStrings[1] = SHARES_REGISTRY_PATH;
  1388. SsLogEvent(
  1389. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1390. 2,
  1391. subStrings,
  1392. RtlNtStatusToDosError( status )
  1393. );
  1394. IF_DEBUG(REGISTRY) {
  1395. SS_PRINT(( "GetStickyShareInfo: Second query failed! Ignoring "
  1396. "share.\n" ));
  1397. }
  1398. goto errorexit;
  1399. }
  1400. //
  1401. // Get the remark. It may be omitted.
  1402. //
  1403. RtlInitUnicodeString( &variableNameString, REMARK_VARIABLE_NAME );
  1404. RemarkString->MaximumLength = 0;
  1405. status = RtlQueryEnvironmentVariable_U(
  1406. ValueData,
  1407. &variableNameString,
  1408. RemarkString
  1409. );
  1410. if ( status == STATUS_BUFFER_TOO_SMALL ) {
  1411. RemarkString->MaximumLength =
  1412. (USHORT)(RemarkString->Length + sizeof(WCHAR));
  1413. RemarkString->Buffer =
  1414. MIDL_user_allocate( RemarkString->MaximumLength );
  1415. if ( RemarkString->Buffer == NULL ) {
  1416. //
  1417. // No space for remark. Ignore this share.
  1418. //
  1419. subStrings[0] = ValueName;
  1420. subStrings[1] = SHARES_REGISTRY_PATH;
  1421. SsLogEvent(
  1422. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1423. 2,
  1424. subStrings,
  1425. ERROR_NOT_ENOUGH_MEMORY
  1426. );
  1427. IF_DEBUG(REGISTRY) {
  1428. SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
  1429. "share.\n" ));
  1430. }
  1431. goto errorexit;
  1432. }
  1433. status = RtlQueryEnvironmentVariable_U(
  1434. ValueData,
  1435. &variableNameString,
  1436. RemarkString
  1437. );
  1438. if ( !NT_SUCCESS(status) ) {
  1439. //
  1440. // Huh? The second attempt failed. Ignore this share.
  1441. //
  1442. subStrings[0] = ValueName;
  1443. subStrings[1] = SHARES_REGISTRY_PATH;
  1444. SsLogEvent(
  1445. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1446. 2,
  1447. subStrings,
  1448. RtlNtStatusToDosError( status )
  1449. );
  1450. IF_DEBUG(REGISTRY) {
  1451. SS_PRINT(( "GetStickyShareInfo: Second query failed! "
  1452. "Ignoring share.\n" ));
  1453. }
  1454. goto errorexit;
  1455. }
  1456. }
  1457. //
  1458. // Get the share type. It may be omitted.
  1459. //
  1460. RtlInitUnicodeString( &variableNameString, TYPE_VARIABLE_NAME );
  1461. unicodeString.Buffer = integerStringBuffer;
  1462. unicodeString.MaximumLength = 35;
  1463. status = RtlQueryEnvironmentVariable_U(
  1464. ValueData,
  1465. &variableNameString,
  1466. &unicodeString
  1467. );
  1468. if ( !NT_SUCCESS(status) ) {
  1469. shi502->shi502_type = STYPE_DISKTREE;
  1470. } else {
  1471. status = RtlUnicodeStringToInteger(
  1472. &unicodeString,
  1473. 0,
  1474. &shi502->shi502_type
  1475. );
  1476. if ( !NT_SUCCESS(status) ) {
  1477. subStrings[0] = ValueName;
  1478. subStrings[1] = SHARES_REGISTRY_PATH;
  1479. SsLogEvent(
  1480. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1481. 2,
  1482. subStrings,
  1483. RtlNtStatusToDosError( status )
  1484. );
  1485. IF_DEBUG(REGISTRY) {
  1486. SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
  1487. "%lx\n", status ));
  1488. }
  1489. goto errorexit;
  1490. }
  1491. }
  1492. //
  1493. // Get the share permissions. It may be omitted.
  1494. //
  1495. RtlInitUnicodeString( &variableNameString, PERMISSIONS_VARIABLE_NAME );
  1496. status = RtlQueryEnvironmentVariable_U(
  1497. ValueData,
  1498. &variableNameString,
  1499. &unicodeString
  1500. );
  1501. if ( !NT_SUCCESS(status) ) {
  1502. shi502->shi502_permissions = 0;
  1503. } else {
  1504. DWORD permissions;
  1505. status = RtlUnicodeStringToInteger(
  1506. &unicodeString,
  1507. 0,
  1508. &permissions
  1509. );
  1510. if ( !NT_SUCCESS(status) ) {
  1511. subStrings[0] = ValueName;
  1512. subStrings[1] = SHARES_REGISTRY_PATH;
  1513. SsLogEvent(
  1514. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1515. 2,
  1516. subStrings,
  1517. RtlNtStatusToDosError( status )
  1518. );
  1519. IF_DEBUG(REGISTRY) {
  1520. SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
  1521. "%lx\n", status ));
  1522. }
  1523. goto errorexit;
  1524. }
  1525. shi502->shi502_permissions = permissions;
  1526. }
  1527. //
  1528. // Get the maximum number of uses allowed. It may be omitted.
  1529. //
  1530. RtlInitUnicodeString( &variableNameString, MAXUSES_VARIABLE_NAME );
  1531. status = RtlQueryEnvironmentVariable_U(
  1532. ValueData,
  1533. &variableNameString,
  1534. &unicodeString
  1535. );
  1536. if ( !NT_SUCCESS(status) ) {
  1537. shi502->shi502_max_uses = (DWORD)SHI_USES_UNLIMITED;
  1538. } else {
  1539. status = RtlUnicodeStringToInteger(
  1540. &unicodeString,
  1541. 0,
  1542. &shi502->shi502_max_uses
  1543. );
  1544. if ( !NT_SUCCESS(status) ) {
  1545. subStrings[0] = ValueName;
  1546. subStrings[1] = SHARES_REGISTRY_PATH;
  1547. SsLogEvent(
  1548. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1549. 2,
  1550. subStrings,
  1551. RtlNtStatusToDosError( status )
  1552. );
  1553. goto errorexit;
  1554. }
  1555. }
  1556. //
  1557. // Get the Cacheing flags. It may be omitted.
  1558. //
  1559. RtlInitUnicodeString( &variableNameString, CSC_VARIABLE_NAME );
  1560. *CacheState = 0;
  1561. status = RtlQueryEnvironmentVariable_U(
  1562. ValueData,
  1563. &variableNameString,
  1564. &unicodeString
  1565. );
  1566. if( NT_SUCCESS( status ) ) {
  1567. ULONG value;
  1568. status = RtlUnicodeStringToInteger(
  1569. &unicodeString,
  1570. 0,
  1571. &value
  1572. );
  1573. if( NT_SUCCESS( status ) ) {
  1574. *CacheState = (value & SHI1005_VALID_FLAGS_SET);
  1575. } else {
  1576. subStrings[0] = ValueName;
  1577. subStrings[1] = SHARES_REGISTRY_PATH;
  1578. SsLogEvent(
  1579. EVENT_SRV_INVALID_REGISTRY_VALUE,
  1580. 2,
  1581. subStrings,
  1582. RtlNtStatusToDosError( status )
  1583. );
  1584. }
  1585. }
  1586. {
  1587. //
  1588. // Get the Share file security descriptor
  1589. //
  1590. RTL_QUERY_REGISTRY_TABLE shareQueryTable[2];
  1591. //
  1592. // Fill up the query table
  1593. //
  1594. shareQueryTable[0].QueryRoutine = GetSdFromRegistry;
  1595. shareQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  1596. shareQueryTable[0].Name = shi502->shi502_netname;
  1597. shareQueryTable[0].EntryContext = NULL;
  1598. shareQueryTable[0].DefaultType = REG_NONE;
  1599. shareQueryTable[1].QueryRoutine = NULL;
  1600. shareQueryTable[1].Flags = 0;
  1601. shareQueryTable[1].Name = NULL;
  1602. status = RtlQueryRegistryValues(
  1603. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1604. SHARES_SECURITY_REGISTRY_PATH,
  1605. shareQueryTable,
  1606. shi502,
  1607. NULL
  1608. );
  1609. if ( !NT_SUCCESS( status) &&
  1610. ( status != STATUS_OBJECT_NAME_NOT_FOUND ) ) {
  1611. ASSERT(0);
  1612. IF_DEBUG(REGISTRY) {
  1613. SS_PRINT(( "GetStickyShareInfo: Get file SD: "
  1614. "%lx\n", status ));
  1615. }
  1616. goto errorexit;
  1617. }
  1618. }
  1619. return TRUE;
  1620. errorexit:
  1621. if ( RemarkString->Buffer != NULL ) {
  1622. RtlFreeUnicodeString( RemarkString );
  1623. }
  1624. if ( PathString->Buffer != NULL ) {
  1625. RtlFreeUnicodeString( PathString );
  1626. }
  1627. if ( shi502->shi502_security_descriptor != NULL ) {
  1628. MIDL_user_free( shi502->shi502_security_descriptor );
  1629. }
  1630. return FALSE;
  1631. } // GetStickyShareInfo
  1632. BOOLEAN
  1633. SsGetDefaultSdFromRegistry (
  1634. IN PWCH ValueName,
  1635. OUT PSECURITY_DESCRIPTOR *FileSD
  1636. )
  1637. /*++
  1638. Routine Description:
  1639. Reads 'ValueName' from the registry and gets the security descriptor
  1640. stored there.
  1641. Arguments:
  1642. ValueName - The name of the registry value in the Parameters section holding the descriptor
  1643. FileSD - points to the allocated SD if one was obtained
  1644. Return Value:
  1645. NTSTATUS - success/failure of the operation.
  1646. --*/
  1647. {
  1648. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1649. SHARE_INFO_502 shi502 = {0};
  1650. NTSTATUS status;
  1651. *FileSD = NULL;
  1652. queryTable[0].QueryRoutine = GetSdFromRegistry;
  1653. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  1654. queryTable[0].Name = ValueName;
  1655. queryTable[0].EntryContext = NULL;
  1656. queryTable[0].DefaultType = REG_NONE;
  1657. queryTable[1].QueryRoutine = NULL;
  1658. queryTable[1].Flags = 0;
  1659. queryTable[1].Name = NULL;
  1660. status = RtlQueryRegistryValues(
  1661. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1662. SHARES_DEFAULT_SECURITY_REGISTRY_PATH,
  1663. queryTable,
  1664. &shi502,
  1665. NULL
  1666. );
  1667. if ( NT_SUCCESS( status) ) {
  1668. IF_DEBUG(INITIALIZATION) {
  1669. SS_PRINT(( "SsGetDefaultSdFromRegistry: using %ws SD from registry.\n",
  1670. ValueName ));
  1671. }
  1672. *FileSD = shi502.shi502_security_descriptor;
  1673. return TRUE;
  1674. }
  1675. return FALSE;
  1676. }
  1677. VOID
  1678. SsWriteDefaultSdToRegistry (
  1679. IN PWCH ValueName,
  1680. IN PSECURITY_DESCRIPTOR FileSD
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. Stores FileSD to 'ValueName' in the registry
  1685. Arguments:
  1686. ValueName - The name of the registry value in the Parameters section holding the descriptor
  1687. FileSD - points to the SD to write
  1688. --*/
  1689. {
  1690. ULONG fileSDLength;
  1691. if ( RtlValidSecurityDescriptor( FileSD ) ) {
  1692. fileSDLength = RtlLengthSecurityDescriptor( FileSD );
  1693. RtlWriteRegistryValue(
  1694. RTL_REGISTRY_SERVICES,
  1695. SHARES_DEFAULT_SECURITY_REGISTRY_PATH,
  1696. ValueName,
  1697. REG_BINARY,
  1698. (LPBYTE)FileSD,
  1699. fileSDLength
  1700. );
  1701. }
  1702. }
  1703. LONG
  1704. LoadParameters (
  1705. PWCH Path
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Reads the registry to get server parameters.
  1710. Arguments:
  1711. Path - PARAMETERS_REGISTRY_PATH or AUTOTUNED_REGISTRY_PATH
  1712. Return Value:
  1713. LONG - success/failure of the operation.
  1714. --*/
  1715. {
  1716. NTSTATUS status;
  1717. PRTL_QUERY_REGISTRY_TABLE queryTable;
  1718. ULONG numberOfBindings = 0;
  1719. //
  1720. // Ask the RTL to call us back for each value in the appropriate
  1721. // key.
  1722. //
  1723. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  1724. if ( queryTable != NULL ) {
  1725. queryTable[0].QueryRoutine = SetStickyParameter;
  1726. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  1727. queryTable[0].Name = NULL;
  1728. queryTable[0].EntryContext = NULL;
  1729. queryTable[0].DefaultType = REG_NONE;
  1730. queryTable[0].DefaultData = NULL;
  1731. queryTable[0].DefaultLength = 0;
  1732. queryTable[1].QueryRoutine = NULL;
  1733. queryTable[1].Flags = 0;
  1734. queryTable[1].Name = NULL;
  1735. status = RtlQueryRegistryValues(
  1736. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1737. Path,
  1738. queryTable,
  1739. Path, // Context for SetStickyParameter
  1740. NULL
  1741. );
  1742. MIDL_user_free( queryTable );
  1743. } else {
  1744. status = STATUS_INSUFFICIENT_RESOURCES;
  1745. }
  1746. if ( !NT_SUCCESS(status) ) {
  1747. IF_DEBUG(INITIALIZATION) {
  1748. SS_PRINT(( "LoadParameters: RtlQueryRegistryValues failed: "
  1749. "%lx\n", status ));
  1750. }
  1751. return RtlNtStatusToDosError( status );
  1752. }
  1753. return NO_ERROR;
  1754. } // LoadParameters
  1755. LONG
  1756. LoadSizeParameter (
  1757. VOID
  1758. )
  1759. /*++
  1760. Routine Description:
  1761. Reads the registry to get the basic server Size parameter.
  1762. Arguments:
  1763. None.
  1764. Return Value:
  1765. LONG - success/failure of the operation.
  1766. --*/
  1767. {
  1768. NTSTATUS status;
  1769. PRTL_QUERY_REGISTRY_TABLE queryTable;
  1770. ULONG numberOfBindings = 0;
  1771. NT_PRODUCT_TYPE productType;
  1772. //
  1773. // Get the product type.
  1774. //
  1775. if ( !RtlGetNtProductType( &productType ) ) {
  1776. productType = NtProductWinNt;
  1777. }
  1778. SsData.ServerInfo598.sv598_producttype = productType;
  1779. //
  1780. // Ask the RTL to call us back if the Size parameter exists.
  1781. //
  1782. queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
  1783. if ( queryTable != NULL ) {
  1784. queryTable[0].QueryRoutine = SetSizeParameters;
  1785. queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  1786. queryTable[0].Name = SIZE_VALUE_NAME;
  1787. queryTable[0].EntryContext = NULL;
  1788. queryTable[0].DefaultType = REG_NONE;
  1789. queryTable[0].DefaultData = NULL;
  1790. queryTable[0].DefaultLength = 0;
  1791. queryTable[1].QueryRoutine = NULL;
  1792. queryTable[1].Flags = 0;
  1793. queryTable[1].Name = NULL;
  1794. status = RtlQueryRegistryValues(
  1795. RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  1796. PARAMETERS_REGISTRY_PATH,
  1797. queryTable,
  1798. NULL,
  1799. NULL
  1800. );
  1801. MIDL_user_free( queryTable );
  1802. } else {
  1803. status = STATUS_INSUFFICIENT_RESOURCES;
  1804. }
  1805. if ( !NT_SUCCESS(status) ) {
  1806. IF_DEBUG(INITIALIZATION) {
  1807. SS_PRINT(( "LoadSizeParameter: RtlQueryRegistryValues failed: "
  1808. "%lx\n", status ));
  1809. }
  1810. return RtlNtStatusToDosError( status );
  1811. }
  1812. return NO_ERROR;
  1813. } // LoadSizeParameter
  1814. VOID
  1815. PrintShareAnnounce (
  1816. LPVOID event
  1817. )
  1818. {
  1819. ULONG i;
  1820. //
  1821. // Announce ourselves and then wait for awhile.
  1822. // If the event gets signaled, terminate the loop and this thread.
  1823. // But don't do this forever, since the print subsystem may actually
  1824. // get stuck
  1825. //
  1826. //
  1827. // Do it for 15 minutes
  1828. //
  1829. for( i=0; i < 60; i++ ) {
  1830. AnnounceServiceStatus( 1 );
  1831. if( WaitForSingleObject( (HANDLE)event, 15*1000 ) != WAIT_TIMEOUT ) {
  1832. break;
  1833. }
  1834. }
  1835. }
  1836. NTSTATUS
  1837. RecreateStickyShare (
  1838. IN PWSTR ValueName,
  1839. IN ULONG ValueType,
  1840. IN PVOID ValueData,
  1841. IN ULONG ValueLength,
  1842. IN PULONG IterationCount,
  1843. IN PVOID EntryContext
  1844. )
  1845. {
  1846. NET_API_STATUS error;
  1847. SHARE_INFO_502 shi502;
  1848. SHARE_INFO shareInfo;
  1849. UNICODE_STRING pathString;
  1850. UNICODE_STRING remarkString;
  1851. HANDLE threadHandle = NULL;
  1852. HANDLE event = NULL;
  1853. DWORD CacheState;
  1854. SHARE_INFO shareInfoBuffer;
  1855. SHARE_INFO_1005 si1005;
  1856. ValueLength, EntryContext;
  1857. remarkString.Buffer = NULL;
  1858. pathString.Buffer = NULL;
  1859. if ( GetStickyShareInfo(
  1860. ValueName,
  1861. ValueType,
  1862. ValueData,
  1863. &remarkString,
  1864. &pathString,
  1865. &shi502,
  1866. &CacheState
  1867. ) ) {
  1868. //
  1869. // Do the actual add of the share.
  1870. //
  1871. IF_DEBUG(INITIALIZATION) {
  1872. SS_PRINT(( "RecreateStickyShares: adding share %ws\n", ValueName ));
  1873. }
  1874. shi502.shi502_remark = remarkString.Buffer;
  1875. shi502.shi502_path = pathString.Buffer;
  1876. shareInfo.ShareInfo502 = (LPSHARE_INFO_502_I)&shi502;
  1877. if( shi502.shi502_type == STYPE_PRINTQ ) {
  1878. //
  1879. // A really big problem is that FAX printers can take aribitrarily long to
  1880. // complete the eventual OpenPrinter() call which the server will make back
  1881. // up to srvsvc. And if we don't announce ourselves in the interval, the
  1882. // service controller will presume that we got stuck on startup. Since
  1883. // NetrShareAdd() is synchronous, we need to get a different thread to
  1884. // announce our service status until NetrShareAdd returns. So, start it
  1885. // now. This is most unfortunate.
  1886. event = CreateEvent( NULL, TRUE, FALSE, NULL );
  1887. if( event != NULL ) {
  1888. DWORD threadId;
  1889. threadHandle = CreateThread(
  1890. NULL,
  1891. 0,
  1892. (LPTHREAD_START_ROUTINE)PrintShareAnnounce,
  1893. (LPVOID)event,
  1894. 0,
  1895. &threadId
  1896. );
  1897. if( threadHandle == NULL ) {
  1898. CloseHandle( event );
  1899. event = NULL;
  1900. }
  1901. }
  1902. }
  1903. //
  1904. // RecreateStickyShare is called during server initialization. The service
  1905. // controller will presume that we're stuck if we don't update our status
  1906. // with it often enough. So every 64 recreated shares we call back to it.
  1907. // There's nothing magic about the 64 -- easy to check for, and not too often.
  1908. //
  1909. if( (shi502.shi502_type == STYPE_PRINTQ && threadHandle == NULL) ||
  1910. (++(*IterationCount) & 63 ) == 0 ) {
  1911. AnnounceServiceStatus( 1 );
  1912. }
  1913. error = NetrShareAdd( NULL, 502, &shareInfo, NULL );
  1914. if( event != NULL ) {
  1915. //
  1916. // We created an announcement thread, set the event telling it to terminate
  1917. //
  1918. SetEvent( event );
  1919. //
  1920. // Wait for the thread to terminate
  1921. //
  1922. if( WaitForSingleObject( threadHandle, INFINITE ) == WAIT_FAILED ) {
  1923. error = GetLastError();
  1924. }
  1925. //
  1926. // Close the handles
  1927. //
  1928. CloseHandle( event );
  1929. CloseHandle( threadHandle );
  1930. }
  1931. if ( error != NO_ERROR ) {
  1932. IF_DEBUG(INITIALIZATION_ERRORS) {
  1933. SS_PRINT(( "RecreateStickyShares: failed to add share "
  1934. "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
  1935. }
  1936. }
  1937. //
  1938. // If this is a share which can be cached, set the caching flag in the server
  1939. //
  1940. si1005.shi1005_flags = CacheState;
  1941. if( si1005.shi1005_flags ) {
  1942. shareInfoBuffer.ShareInfo1005 = &si1005;
  1943. NetrShareSetInfo( NULL, ValueName, 1005, &shareInfoBuffer, NULL );
  1944. }
  1945. //
  1946. // free buffers allocated by GetStickyShareInfo
  1947. //
  1948. if ( remarkString.Buffer != NULL ) {
  1949. RtlFreeUnicodeString( &remarkString );
  1950. }
  1951. if ( pathString.Buffer != NULL ) {
  1952. RtlFreeUnicodeString( &pathString );
  1953. }
  1954. if ( shi502.shi502_security_descriptor != NULL ) {
  1955. MIDL_user_free( shi502.shi502_security_descriptor );
  1956. }
  1957. }
  1958. return NO_ERROR;
  1959. } // RecreateStickyShare
  1960. NTSTATUS
  1961. SaveSdToRegistry(
  1962. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1963. IN PWSTR ShareName
  1964. )
  1965. /*++
  1966. Routine Description:
  1967. Stores the share file security descriptor in the registry.
  1968. Arguments:
  1969. SecurityDescriptor - Points to a self-relative security descriptor
  1970. describing the access rights for files under this share.
  1971. ShareName - Points to a string containing the share name under
  1972. which the SD is to be stored.
  1973. Return Value:
  1974. Status of the operation.
  1975. --*/
  1976. {
  1977. NTSTATUS status;
  1978. //
  1979. // Store the security descriptor
  1980. //
  1981. ULONG fileSDLength;
  1982. if ( !RtlValidSecurityDescriptor( SecurityDescriptor ) ) {
  1983. status = STATUS_INVALID_SECURITY_DESCR;
  1984. } else {
  1985. fileSDLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  1986. status = RtlWriteRegistryValue(
  1987. RTL_REGISTRY_SERVICES,
  1988. SHARES_SECURITY_REGISTRY_PATH,
  1989. ShareName,
  1990. REG_BINARY,
  1991. (LPBYTE)SecurityDescriptor,
  1992. fileSDLength
  1993. );
  1994. }
  1995. return status;
  1996. } // SaveSdToRegistry
  1997. NTSTATUS
  1998. SetSizeParameters (
  1999. IN PWSTR ValueName,
  2000. IN ULONG ValueType,
  2001. IN PVOID ValueData,
  2002. IN ULONG ValueLength,
  2003. IN PVOID Context,
  2004. IN PVOID EntryContext
  2005. )
  2006. {
  2007. DWORD size;
  2008. LPWSTR subStrings[2];
  2009. ValueLength, Context, EntryContext;
  2010. //
  2011. // Make sure that we got called for the right value.
  2012. //
  2013. ASSERT( _wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0 );
  2014. //
  2015. // The Size value must be a DWORD, and must be in the following
  2016. // range:
  2017. //
  2018. // 0 -> use defaults
  2019. // 1 -> small server (minimize memory usage)
  2020. // 2 -> medium server (balance)
  2021. // 3 -> large server (maximize connections)
  2022. //
  2023. if ( ValueType == REG_DWORD ) {
  2024. ASSERT( ValueLength == sizeof(DWORD) );
  2025. size = *(LPDWORD)ValueData;
  2026. }
  2027. if ( (ValueType != REG_DWORD) || (size > 3) ) {
  2028. subStrings[0] = ValueName;
  2029. subStrings[1] = PARAMETERS_REGISTRY_PATH;
  2030. SsLogEvent(
  2031. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2032. 2,
  2033. subStrings,
  2034. NO_ERROR
  2035. );
  2036. IF_DEBUG(REGISTRY) {
  2037. SS_PRINT(( "SetSizeParameters: skipping invalid value "
  2038. "%ws\n", ValueName ));
  2039. }
  2040. return STATUS_SUCCESS;
  2041. }
  2042. SsData.ServerInfo598.sv598_serversize = size;
  2043. //
  2044. // Set appropriate fields based on the product type (Windows NT or
  2045. // Advanced Server) and the selected Size. Note that a Size of 0
  2046. // doesn't change any of the defaults.
  2047. //
  2048. // Note that the user limit is always -1 (unlimited). Autodisconnect
  2049. // always defaults to 15 minutes.
  2050. //
  2051. if ( size != 0 ) {
  2052. SYSTEM_BASIC_INFORMATION basicInfo;
  2053. NTSTATUS status;
  2054. ULONG noOfMb;
  2055. ULONG factor;
  2056. ULONG asFactor;
  2057. //
  2058. // Get system memory size.
  2059. //
  2060. status = NtQuerySystemInformation(
  2061. SystemBasicInformation,
  2062. &basicInfo,
  2063. sizeof( SYSTEM_BASIC_INFORMATION ),
  2064. NULL
  2065. );
  2066. if ( status != STATUS_SUCCESS ) {
  2067. subStrings[0] = ValueName;
  2068. subStrings[1] = PARAMETERS_REGISTRY_PATH;
  2069. SsLogEvent(
  2070. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2071. 2,
  2072. subStrings,
  2073. NO_ERROR
  2074. );
  2075. IF_DEBUG(REGISTRY) {
  2076. SS_PRINT(( "SetSizeParameters: NtQuerySystemInfo failed %x\n",
  2077. status ));
  2078. }
  2079. return STATUS_SUCCESS;
  2080. }
  2081. //
  2082. // Note that we first divide the page size by 512 in order to
  2083. // allow for physical memory sizes above 2^32-1. With this
  2084. // calculation, we can handle up to two terabytes of physical
  2085. // memory. The calculation assumes that the page size is at
  2086. // least 512, and is not very accurate if the page size is not
  2087. // a power of 2 (very unlikely).
  2088. //
  2089. ASSERT( basicInfo.PageSize >= 512 );
  2090. noOfMb = (ULONG)(((basicInfo.PageSize / 512) *
  2091. basicInfo.NumberOfPhysicalPages) +
  2092. (1 MB / 512 - 1)) / (1 MB / 512);
  2093. //
  2094. // Minimum is 8 MB
  2095. //
  2096. noOfMb = MAX( MIN_SYSTEM_SIZE, noOfMb );
  2097. //
  2098. // If we have NTAS, and we're set to maximize performance or we have
  2099. // lots of memory -- then set the default work item buffer size to
  2100. // a larger value. This value has been chosen to work well with our
  2101. // implementation of TCP/IP, and shows itself to advantage when doing
  2102. // directory emumerations with directories having lots of entries in them.
  2103. //
  2104. if( SsData.ServerInfo598.sv598_producttype != NtProductWinNt && ((noOfMb >= 512) && (size == 3)) ) {
  2105. SsData.ServerInfo599.sv599_sizreqbuf = DEF_LARGE_SIZREQBUF;
  2106. }
  2107. //
  2108. // Set the maximum for the different sizes
  2109. //
  2110. if ( size == 1 ) {
  2111. noOfMb = MIN( noOfMb, MAX_SMALL_SIZE );
  2112. } else if ( size == 2 ) {
  2113. noOfMb = MIN( noOfMb, MAX_MEDIUM_SIZE );
  2114. }
  2115. //
  2116. // If small, assume the system size is half of the real one.
  2117. // This should give us half the paramater values of a medium server.
  2118. // If large, double it. Also set the free connection count.
  2119. //
  2120. if ( size == 1 ) {
  2121. //
  2122. // Small
  2123. //
  2124. factor = (noOfMb + 1) / 2;
  2125. SsData.ServerInfo599.sv599_minfreeconnections = 2;
  2126. SsData.ServerInfo599.sv599_maxfreeconnections = 2;
  2127. } else if ( size == 2 ) {
  2128. //
  2129. // Balanced
  2130. //
  2131. factor = noOfMb;
  2132. SsData.ServerInfo599.sv599_minfreeconnections = 2;
  2133. SsData.ServerInfo599.sv599_maxfreeconnections = 4;
  2134. } else {
  2135. //
  2136. // Large
  2137. //
  2138. factor = noOfMb * 2;
  2139. // Scale up our big servers, this uses the NEW version of small/med/large we picked
  2140. // for the server service (< 1 GB, 1-16 GB, >16 GB)
  2141. if( noOfMb < 1024 )
  2142. {
  2143. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_SMALL;
  2144. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_SMALL;
  2145. }
  2146. else if( noOfMb < 16*1024 )
  2147. {
  2148. // >= 1 GB memory
  2149. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_MEDIUM;
  2150. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_MEDIUM;
  2151. }
  2152. else {
  2153. // >= 16 GB memory
  2154. SsData.ServerInfo599.sv599_minfreeconnections = SRV_MIN_CONNECTIONS_LARGE;
  2155. SsData.ServerInfo599.sv599_maxfreeconnections = SRV_MAX_CONNECTIONS_LARGE;
  2156. }
  2157. }
  2158. //
  2159. // If this is an Advanced Server with at least 24M, some
  2160. // parameter will need to be even bigger.
  2161. //
  2162. asFactor = 1;
  2163. if ( (SsData.ServerInfo598.sv598_producttype != NtProductWinNt) && (noOfMb >= 24) ) asFactor = 2;
  2164. //
  2165. // Now set the values for a medium server with this much memory.
  2166. //
  2167. SsData.ServerInfo599.sv599_maxworkitems =
  2168. MedSrvCfgTbl.maxworkitems[0] * factor * asFactor /
  2169. MedSrvCfgTbl.maxworkitems[1];
  2170. SsData.ServerInfo599.sv599_initworkitems =
  2171. MedSrvCfgTbl.initworkitems[0] * factor * asFactor /
  2172. MedSrvCfgTbl.initworkitems[1];
  2173. SsData.ServerInfo599.sv599_rawworkitems =
  2174. MedSrvCfgTbl.rawworkitems[0] * factor /
  2175. MedSrvCfgTbl.rawworkitems[1];
  2176. SsData.ServerInfo598.sv598_maxrawworkitems =
  2177. MedSrvCfgTbl.maxrawworkitems[0] * factor * asFactor /
  2178. MedSrvCfgTbl.maxrawworkitems[1];
  2179. SsData.ServerInfo599.sv599_maxworkitems =
  2180. MIN( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS );
  2181. SsData.ServerInfo599.sv599_initworkitems =
  2182. MIN( SsData.ServerInfo599.sv599_initworkitems, MAX_INITWORKITEMS/4 );
  2183. SsData.ServerInfo599.sv599_rawworkitems =
  2184. MIN( SsData.ServerInfo599.sv599_rawworkitems, MAX_RAWWORKITEMS/4 );
  2185. SsData.ServerInfo598.sv598_maxrawworkitems =
  2186. MIN( SsData.ServerInfo598.sv598_maxrawworkitems, MAX_MAXRAWWORKITEMS );
  2187. if ( (SsData.ServerInfo598.sv598_producttype != NtProductWinNt) || (size == 3) ) {
  2188. SsData.ServerInfo599.sv599_maxpagedmemoryusage = INF;
  2189. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage = INF;
  2190. } else {
  2191. SsData.ServerInfo599.sv599_maxpagedmemoryusage =
  2192. MedSrvCfgTbl.maxpagedmemoryusage[0] * factor /
  2193. MedSrvCfgTbl.maxpagedmemoryusage[1] MB;
  2194. SsData.ServerInfo599.sv599_maxpagedmemoryusage =
  2195. MAX( SsData.ServerInfo599.sv599_maxpagedmemoryusage,
  2196. MIN_MAXPAGEDMEMORYUSAGE);
  2197. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
  2198. MedSrvCfgTbl.maxnonpagedmemoryusage[0] * factor /
  2199. MedSrvCfgTbl.maxnonpagedmemoryusage[1] MB;
  2200. SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
  2201. MAX( SsData.ServerInfo599.sv599_maxnonpagedmemoryusage,
  2202. MIN_MAXNONPAGEDMEMORYUSAGE);
  2203. }
  2204. }
  2205. return STATUS_SUCCESS;
  2206. } // SetSizeParameters
  2207. NTSTATUS
  2208. SetStickyParameter (
  2209. IN PWSTR ValueName,
  2210. IN ULONG ValueType,
  2211. IN PVOID ValueData,
  2212. IN ULONG ValueLength,
  2213. IN PVOID Context,
  2214. IN PVOID EntryContext
  2215. )
  2216. {
  2217. NET_API_STATUS error;
  2218. DWORD_PTR i;
  2219. PFIELD_DESCRIPTOR foundField = NULL;
  2220. LPWSTR subStrings[2];
  2221. ValueLength, EntryContext;
  2222. //
  2223. // Ignore several parameters, since they are handled elsewhere
  2224. //
  2225. if( (_wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0) ||
  2226. (_wcsicmp( ValueName, NULL_SESSION_SHARES_VALUE_NAME ) == 0) ||
  2227. (_wcsicmp( ValueName, NULL_SESSION_PIPES_VALUE_NAME ) == 0) ||
  2228. (_wcsicmp( ValueName, PIPES_NEED_LICENSE_VALUE_NAME ) == 0) ||
  2229. (_wcsicmp( ValueName, ERROR_LOG_IGNORE_VALUE_NAME ) == 0) ||
  2230. (_wcsicmp( ValueName, GUID_VARIABLE_NAME ) == 0) ||
  2231. (_wcsicmp( ValueName, OPTIONAL_NAMES_VALUE_NAME ) == 0) ||
  2232. (_wcsicmp( ValueName, NO_REMAP_PIPES_VALUE_NAME ) == 0) ||
  2233. (_wcsicmp( ValueName, SERVICE_DLL_VALUE_NAME ) == 0) ) {
  2234. return STATUS_SUCCESS;
  2235. }
  2236. //
  2237. // Determine which field we need to set, based on the value
  2238. // name.
  2239. //
  2240. // NOTE: For Daytona, disc and comment are now invalid registry names.
  2241. // We use their more famous aliases autodisconnect and srvcomment
  2242. // instead. If we get more of these cases, we should consider adding
  2243. // a field to the FIELD_DESCRIPTOR structure that indicates whether
  2244. // the names are should appear on the registry or not. Any change
  2245. // here should also be made to SsSetField().
  2246. //
  2247. if ( (_wcsicmp( ValueName, DISC_VALUE_NAME ) != 0) &&
  2248. (_wcsicmp( ValueName, COMMENT_VALUE_NAME ) != 0) ) {
  2249. for ( i = 0;
  2250. SsServerInfoFields[i].FieldName != NULL;
  2251. i++ ) {
  2252. if ( _wcsicmp( ValueName, SsServerInfoFields[i].FieldName ) == 0 ) {
  2253. foundField = &SsServerInfoFields[i];
  2254. break;
  2255. }
  2256. }
  2257. }
  2258. if ( foundField == NULL || foundField->Settable == NOT_SETTABLE ) {
  2259. #ifdef DBG
  2260. subStrings[0] = ValueName;
  2261. subStrings[1] = Context;
  2262. SsLogEvent(
  2263. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2264. 2,
  2265. subStrings,
  2266. NO_ERROR
  2267. );
  2268. IF_DEBUG(REGISTRY) {
  2269. SS_PRINT(( "SetStickyParameter: ignoring %s \"%ws\"\n",
  2270. (foundField == NULL ? "unknown value name" :
  2271. "unsettable value"), ValueName ));
  2272. }
  2273. #endif
  2274. return STATUS_SUCCESS;
  2275. }
  2276. switch ( foundField->FieldType ) {
  2277. case BOOLEAN_FIELD:
  2278. case DWORD_FIELD:
  2279. if ( ValueType != REG_DWORD ) {
  2280. subStrings[0] = ValueName;
  2281. subStrings[1] = Context;
  2282. SsLogEvent(
  2283. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2284. 2,
  2285. subStrings,
  2286. NO_ERROR
  2287. );
  2288. IF_DEBUG(REGISTRY) {
  2289. SS_PRINT(( "SetStickyParameter: skipping invalid value "
  2290. "%ws\n", ValueName ));
  2291. }
  2292. return STATUS_SUCCESS;
  2293. }
  2294. i = *(LPDWORD)ValueData;
  2295. break;
  2296. case LPSTR_FIELD:
  2297. if ( ValueType != REG_SZ ) {
  2298. subStrings[0] = ValueName;
  2299. subStrings[1] = Context;
  2300. SsLogEvent(
  2301. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2302. 2,
  2303. subStrings,
  2304. NO_ERROR
  2305. );
  2306. IF_DEBUG(REGISTRY) {
  2307. SS_PRINT(( "SetStickyParameter: skipping invalid value "
  2308. "%ws\n", ValueName ));
  2309. }
  2310. return STATUS_SUCCESS;
  2311. }
  2312. if (ValueLength != 0) {
  2313. i = (DWORD_PTR)ValueData;
  2314. } else {
  2315. i = (DWORD_PTR)NULL;
  2316. }
  2317. break;
  2318. }
  2319. //
  2320. // Set the field.
  2321. //
  2322. error = SsSetField( foundField, &i, FALSE, NULL );
  2323. #ifdef DBG
  2324. if ( error != NO_ERROR ) {
  2325. subStrings[0] = ValueName;
  2326. subStrings[1] = Context;
  2327. SsLogEvent(
  2328. EVENT_SRV_INVALID_REGISTRY_VALUE,
  2329. 2,
  2330. subStrings,
  2331. error
  2332. );
  2333. IF_DEBUG(REGISTRY) {
  2334. SS_PRINT(( "SetStickyParameter: error %ld ignored in setting "
  2335. "parameter \"%ws\"n", error, ValueName ));
  2336. }
  2337. }
  2338. #endif
  2339. return STATUS_SUCCESS;
  2340. } // SetStickyParameter