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.

1318 lines
35 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: init.c
  7. //
  8. // Description: This module contains code to intialize and de-initialize
  9. // the AFP Server, RPC server, the security object and
  10. // other global vriables.
  11. //
  12. // History:
  13. // May 11,1992. NarenG Created original version.
  14. //
  15. //
  16. #include "afpsvcp.h"
  17. // Prototypes of functions used only within this module.
  18. //
  19. DWORD
  20. AfpInitServerVolumes(
  21. VOID
  22. );
  23. DWORD
  24. AfpInitServerParameters(
  25. VOID
  26. );
  27. DWORD
  28. AfpInitServerIcons(
  29. VOID
  30. );
  31. DWORD
  32. AfpInitETCMaps(
  33. VOID
  34. );
  35. DWORD
  36. AfpInitRPC(
  37. VOID
  38. );
  39. DWORD
  40. AfpInitServerDomainOffsets(
  41. VOID
  42. );
  43. VOID
  44. AfpTerminateRPC(
  45. VOID
  46. );
  47. VOID
  48. AfpIniLsa(
  49. VOID
  50. );
  51. BOOL
  52. IsAfpGuestAccountEnabled(
  53. VOID
  54. );
  55. //**
  56. //
  57. // Call: AfpInitialize
  58. //
  59. // Returns: NO_ERROR
  60. //
  61. // Description: Will do all server intialization.
  62. // 1) Create the security object.
  63. // 2) Set up the server for RPC.
  64. // 3) Open all the registry keys that store AFP data.
  65. // 4) Get the handle to the FSD.
  66. // 5) Get default server parameters
  67. // 6) It will initialize the AFP Server with volume, ETC, icon
  68. // and server parameter information.
  69. // 7) IOCTL the FSD to start the server.
  70. //
  71. DWORD
  72. AfpInitialize(
  73. VOID
  74. )
  75. {
  76. AFP_REQUEST_PACKET AfpRequestPkt;
  77. DWORD dwRetCode;
  78. BOOL fFirstThread;
  79. DWORD nThreads;
  80. // Load strings from resource file
  81. //
  82. if (( !LoadString( GetModuleHandle( NULL ), 1, AfpGlobals.wchUnknown, 100 ))
  83. ||
  84. ( !LoadString( GetModuleHandle( NULL ), 2, AfpGlobals.wchInvalid, 100 ))
  85. ||
  86. ( !LoadString( GetModuleHandle( NULL ), 3, AfpGlobals.wchDeleted, 100 ))
  87. ||
  88. ( !LoadString( GetModuleHandle( NULL ), 4, AfpGlobals.wchDefTCComment,
  89. AFP_ETC_COMMENT_LEN+1 )))
  90. AfpLogEvent( AFPLOG_CANT_LOAD_RESOURCE, 0, NULL,
  91. GetLastError(), EVENTLOG_WARNING_TYPE );
  92. //
  93. // Create the security object
  94. //
  95. if ( dwRetCode = AfpSecObjCreate() ) {
  96. AfpLogEvent( AFPLOG_CANT_CREATE_SECOBJ, 0, NULL,
  97. dwRetCode, EVENTLOG_ERROR_TYPE );
  98. return( dwRetCode );
  99. }
  100. // Initialize the server to accept RPC calls
  101. //
  102. if ( dwRetCode = AfpInitRPC() ) {
  103. AfpLogEvent( AFPLOG_CANT_INIT_RPC, 0, NULL,
  104. dwRetCode, EVENTLOG_ERROR_TYPE );
  105. return( dwRetCode );
  106. }
  107. AfpGlobals.dwServerState |= AFPSTATE_RPC_STARTED;
  108. // Open the registry keys where AFP Server information is stored
  109. //
  110. if ( dwRetCode = AfpRegOpen() ) {
  111. AfpLogEvent( AFPLOG_CANT_OPEN_REGKEY, 0, NULL,
  112. dwRetCode, EVENTLOG_ERROR_TYPE );
  113. return( dwRetCode );
  114. }
  115. AfpGlobals.ServiceStatus.dwCheckPoint++;
  116. AfpAnnounceServiceStatus();
  117. // Open and load the AFP Server FSD and obtain a handle to it
  118. //
  119. if ( dwRetCode = AfpFSDLoad() ) {
  120. AfpLogEvent( AFPLOG_CANT_LOAD_FSD, 0, NULL,
  121. dwRetCode, EVENTLOG_ERROR_TYPE );
  122. return( dwRetCode );
  123. }
  124. AfpGlobals.dwServerState |= AFPSTATE_FSD_LOADED;
  125. if ( dwRetCode = AfpFSDOpen( &(AfpGlobals.hFSD) ) ) {
  126. AfpLogEvent( AFPLOG_CANT_OPEN_FSD, 0, NULL,
  127. dwRetCode, EVENTLOG_ERROR_TYPE );
  128. return( dwRetCode );
  129. }
  130. // Query the product type of server.
  131. //
  132. AfpGlobals.pSidNone = NULL;
  133. RtlGetNtProductType ( &(AfpGlobals.NtProductType) );
  134. // Create the event object for the server helper thread.
  135. //
  136. if ( (AfpGlobals.heventSrvrHlprThread =
  137. CreateEvent( NULL, FALSE, FALSE, NULL ) ) == NULL){
  138. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, GetLastError(),
  139. EVENTLOG_ERROR_TYPE );
  140. return( GetLastError() );
  141. }
  142. // Create the event object for the server helper thread termination.
  143. //
  144. if ( (AfpGlobals.heventSrvrHlprThreadTerminate =
  145. CreateEvent( NULL, FALSE, FALSE, NULL ) ) == NULL){
  146. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, GetLastError(),
  147. EVENTLOG_ERROR_TYPE );
  148. return( GetLastError() );
  149. }
  150. // Create the event object for the "special case" unblocking of server helper thread
  151. //
  152. if ( (AfpGlobals.heventSrvrHlprSpecial =
  153. CreateEvent( NULL, FALSE, FALSE, NULL ) ) == NULL){
  154. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, GetLastError(),
  155. EVENTLOG_ERROR_TYPE );
  156. return( GetLastError() );
  157. }
  158. // Create server helper threads. The parameter indicates if this is the
  159. // first thread that is being created.
  160. //
  161. fFirstThread = TRUE;
  162. nThreads = 0;
  163. do {
  164. if ( ( dwRetCode = AfpCreateServerHelperThread( fFirstThread ) )
  165. != NO_ERROR ) {
  166. AfpLogEvent( AFPLOG_CANT_CREATE_SRVRHLPR, 0, NULL,
  167. dwRetCode, EVENTLOG_ERROR_TYPE );
  168. if ( fFirstThread ) {
  169. AfpLogEvent( AFPLOG_CANT_START, 0, NULL,
  170. dwRetCode, EVENTLOG_ERROR_TYPE );
  171. return( dwRetCode );
  172. }
  173. }
  174. // Wait for the server helper thread to indicate if it successfully
  175. // initialized itself.
  176. //
  177. WaitForSingleObject( AfpGlobals.heventSrvrHlprThread, INFINITE );
  178. if ( AfpGlobals.dwSrvrHlprCode != NO_ERROR ) {
  179. AfpLogEvent(AFPLOG_CANT_INIT_SRVRHLPR,
  180. 0,
  181. NULL,
  182. AfpGlobals.dwSrvrHlprCode,
  183. EVENTLOG_ERROR_TYPE );
  184. if ( fFirstThread )
  185. {
  186. AFP_PRINT( ( "SFMSVC: can't start macfile, first thread failed %ld\n",
  187. AfpGlobals.dwSrvrHlprCode));
  188. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, dwRetCode,
  189. EVENTLOG_ERROR_TYPE );
  190. return( AfpGlobals.dwSrvrHlprCode );
  191. }
  192. }
  193. fFirstThread = FALSE;
  194. }while( ++nThreads < NUM_SECURITY_UTILITY_THREADS );
  195. // Read in server parameters from the registry and intialize the
  196. // server with them.
  197. //
  198. if ( dwRetCode = AfpInitServerParameters())
  199. {
  200. AFP_PRINT( ( "SFMSVC: AfpInitServerParameters failed %ld\n",dwRetCode));
  201. AfpLogEvent( AFPLOG_CANT_INIT_SRVR_PARAMS, 0, NULL, dwRetCode,EVENTLOG_ERROR_TYPE );
  202. return( dwRetCode );
  203. }
  204. AfpGlobals.ServiceStatus.dwCheckPoint++;
  205. AfpAnnounceServiceStatus();
  206. // Read in the ETC Mappings and initialize the AFP Server with them
  207. // Also create a private cache of this information.
  208. //
  209. if ( dwRetCode = AfpInitETCMaps() )
  210. {
  211. AFP_PRINT( ( "SFMSVC: AfpInitETCMaps failed %ld\n",dwRetCode));
  212. AfpLogEvent( AFPLOG_CANT_INIT_ETCINFO, 0, NULL, dwRetCode,EVENTLOG_ERROR_TYPE );
  213. return( dwRetCode );
  214. }
  215. if ( dwRetCode = AfpInitServerIcons() )
  216. {
  217. AFP_PRINT( ( "SFMSVC: AfpInitServerIcons failed %ld\n",dwRetCode));
  218. AfpLogEvent( AFPLOG_CANT_INIT_ICONS, 0, NULL, dwRetCode ,EVENTLOG_ERROR_TYPE );
  219. return( dwRetCode );
  220. }
  221. AfpGlobals.ServiceStatus.dwCheckPoint++;
  222. AfpAnnounceServiceStatus();
  223. // Read in any volumes and initialize the server with them
  224. //
  225. if ( dwRetCode = AfpInitServerVolumes() )
  226. {
  227. AFP_PRINT( ( "SFMSVC: AfpInitServerVolumes failed %ld\n",dwRetCode));
  228. AfpLogEvent( AFPLOG_CANT_INIT_VOLUMES, 0, NULL, dwRetCode,EVENTLOG_ERROR_TYPE );
  229. return( dwRetCode );
  230. }
  231. // Create mutex objects around volume operations to avoid simultaneous
  232. // writing in the registry.
  233. //
  234. if ( (AfpGlobals.hmutexVolume = CreateMutex( NULL, FALSE, NULL ) ) == NULL)
  235. {
  236. AFP_PRINT( ( "SFMSVC: CreateMutex failed in AfpInitialize\n"));
  237. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, dwRetCode,EVENTLOG_ERROR_TYPE );
  238. return( GetLastError() );
  239. }
  240. // Create mutex objects around ETCMap operations.
  241. //
  242. if ( (AfpGlobals.hmutexETCMap = CreateMutex( NULL, FALSE, NULL ) ) == NULL)
  243. {
  244. AFP_PRINT( ( "SFMSVC: CreateMutex 2 failed in AfpInitialize\n"));
  245. AfpLogEvent( AFPLOG_CANT_START, 0, NULL, GetLastError(),EVENTLOG_ERROR_TYPE );
  246. return( GetLastError() );
  247. }
  248. // OK we are all set to go so lets tell the AFP Server to start
  249. //
  250. AfpRequestPkt.dwRequestCode = OP_SERVICE_START;
  251. AfpRequestPkt.dwApiType = AFP_API_TYPE_COMMAND;
  252. AFP_PRINT( ( "SFMSVC: ioctling sfmsrv to start\n"));
  253. if ( dwRetCode = AfpServerIOCtrl( &AfpRequestPkt ) )
  254. {
  255. AFP_PRINT( ( "SFMSVC: AfpServerIOCtrl to start sfmsrv failed %ld\n",dwRetCode));
  256. AfpLogEvent( AFPLOG_CANT_START,0,NULL,dwRetCode,EVENTLOG_ERROR_TYPE);
  257. return( dwRetCode );
  258. }
  259. AfpIniLsa();
  260. return( NO_ERROR );
  261. }
  262. //**
  263. //
  264. // Call: AfpTerminate
  265. //
  266. // Returns: none.
  267. //
  268. // Description: This procedure will shut down the server, and do any
  269. // clean up if required.
  270. //
  271. VOID
  272. AfpTerminate(
  273. VOID
  274. )
  275. {
  276. AFP_REQUEST_PACKET AfpRequestPkt;
  277. DWORD dwRetCode;
  278. // If the FSD was loaded
  279. //
  280. if ( AfpGlobals.dwServerState & AFPSTATE_FSD_LOADED ) {
  281. // Tell the server to shut down
  282. //
  283. AfpRequestPkt.dwRequestCode = OP_SERVICE_STOP;
  284. AfpRequestPkt.dwApiType = AFP_API_TYPE_COMMAND;
  285. if ( dwRetCode = AfpServerIOCtrl( &AfpRequestPkt ) )
  286. AfpLogEvent( AFPLOG_CANT_STOP, 0, NULL,
  287. dwRetCode, EVENTLOG_ERROR_TYPE );
  288. }
  289. AfpGlobals.ServiceStatus.dwCheckPoint++;
  290. AfpAnnounceServiceStatus();
  291. // Try to close the FSD
  292. //
  293. if ( AfpGlobals.hFSD != NULL )
  294. {
  295. if ( dwRetCode = AfpFSDClose( AfpGlobals.hFSD ) )
  296. {
  297. AfpLogEvent( AFPLOG_CANT_STOP, 0, NULL,
  298. dwRetCode, EVENTLOG_ERROR_TYPE );
  299. }
  300. // Try to unload the FSD
  301. //
  302. if ( dwRetCode = AfpFSDUnload() )
  303. {
  304. AfpLogEvent( AFPLOG_CANT_STOP, 0, NULL,
  305. dwRetCode, EVENTLOG_ERROR_TYPE);
  306. }
  307. }
  308. AfpGlobals.ServiceStatus.dwCheckPoint++;
  309. AfpAnnounceServiceStatus();
  310. // Delete the security object.
  311. //
  312. AfpSecObjDelete();
  313. // De-initialize the RPC server
  314. //
  315. AfpTerminateRPC();
  316. // Close the registry keys.
  317. //
  318. AfpRegClose();
  319. // Free the pSidNone if we allocated it for standalone
  320. //
  321. if (AfpGlobals.pSidNone != NULL)
  322. {
  323. LocalFree(AfpGlobals.pSidNone);
  324. AfpGlobals.pSidNone = NULL;
  325. }
  326. if (SfmLsaHandle != NULL)
  327. {
  328. LsaDeregisterLogonProcess( SfmLsaHandle );
  329. SfmLsaHandle = NULL;
  330. }
  331. return;
  332. }
  333. //**
  334. //
  335. // Call: AfpInitServerParameters
  336. //
  337. // Returns: NO_ERROR
  338. // non-zero return codes from the IOCTL or other system calls.
  339. //
  340. // Description: This procedure will set default values for parameters. It
  341. // will then call AfpRegServerGetInfo to override these defaults
  342. // with any parameters that may be stored in the registry. It
  343. // will then initialize the FSD with these parameters.
  344. //
  345. DWORD
  346. AfpInitServerParameters(
  347. VOID
  348. )
  349. {
  350. AFP_SERVER_INFO AfpServerInfo;
  351. DWORD cbServerNameSize;
  352. DWORD dwRetCode;
  353. AFP_REQUEST_PACKET AfpRequestPkt;
  354. // Initialize all the server parameters with defaults
  355. //
  356. cbServerNameSize = sizeof( AfpGlobals.wchServerName );
  357. if ( !GetComputerName( AfpGlobals.wchServerName, &cbServerNameSize ) )
  358. return( GetLastError() );
  359. AfpGlobals.dwMaxSessions = AFP_DEF_MAXSESSIONS;
  360. AfpGlobals.dwServerOptions = AFP_DEF_SRVOPTIONS;
  361. AfpGlobals.wchLoginMsg[0] = TEXT('\0');
  362. AfpGlobals.dwMaxPagedMem = AFP_DEF_MAXPAGEDMEM;
  363. AfpGlobals.dwMaxNonPagedMem = AFP_DEF_MAXNONPAGEDMEM;
  364. // Read in any server parameters in the registry. Registry parameters
  365. // will override the defaults set above.
  366. //
  367. if ( dwRetCode = AfpRegServerGetInfo() )
  368. return( dwRetCode );
  369. if (IsAfpGuestAccountEnabled())
  370. {
  371. AfpGlobals.dwServerOptions |= AFP_SRVROPT_GUESTLOGONALLOWED;
  372. }
  373. else
  374. {
  375. AfpGlobals.dwServerOptions &= ~AFP_SRVROPT_GUESTLOGONALLOWED;
  376. }
  377. // Get the path to the codepage
  378. //
  379. if ( dwRetCode = AfpRegServerGetCodePagePath() )
  380. return( dwRetCode );
  381. // Set up server info structure
  382. //
  383. AfpServerInfo.afpsrv_name = AfpGlobals.wchServerName;
  384. AfpServerInfo.afpsrv_max_sessions = AfpGlobals.dwMaxSessions;
  385. AfpServerInfo.afpsrv_options = AfpGlobals.dwServerOptions;
  386. if (AfpGlobals.NtProductType != NtProductLanManNt)
  387. {
  388. AfpServerInfo.afpsrv_options |= AFP_SRVROPT_STANDALONE;
  389. }
  390. AfpServerInfo.afpsrv_login_msg = AfpGlobals.wchLoginMsg;
  391. AfpServerInfo.afpsrv_max_paged_mem = AfpGlobals.dwMaxPagedMem;
  392. AfpServerInfo.afpsrv_max_nonpaged_mem = AfpGlobals.dwMaxNonPagedMem;
  393. AfpServerInfo.afpsrv_codepage = AfpGlobals.wchCodePagePath;
  394. // Make this buffer self-relative.
  395. //
  396. if ( dwRetCode = AfpBufMakeFSDRequest(
  397. (LPBYTE)&AfpServerInfo,
  398. sizeof(SETINFOREQPKT),
  399. AFP_SERVER_STRUCT,
  400. (LPBYTE*)&(AfpRequestPkt.Type.SetInfo.pInputBuf),
  401. &(AfpRequestPkt.Type.SetInfo.cbInputBufSize)))
  402. {
  403. return( dwRetCode );
  404. }
  405. // IOCTL the FSD to set the server parameters
  406. //
  407. AfpRequestPkt.dwRequestCode = OP_SERVER_SET_INFO;
  408. AfpRequestPkt.dwApiType = AFP_API_TYPE_SETINFO;
  409. AfpRequestPkt.Type.SetInfo.dwParmNum = AFP_SERVER_PARMNUM_ALL;
  410. dwRetCode = AfpServerIOCtrl( &AfpRequestPkt );
  411. LocalFree( AfpRequestPkt.Type.SetInfo.pInputBuf );
  412. return( dwRetCode );
  413. }
  414. //**
  415. //
  416. // Call: AfpInitServerVolumes
  417. //
  418. // Returns: NO_ERROR - success
  419. // ERROR_NOT_ENOUGH_MEMORY
  420. // non-zero return codes from registry apis.
  421. //
  422. // Description: This procedure will read in a volume at a time from the
  423. // registry, and then register this volume with the server.
  424. // This procedure will only return fatal errors that will
  425. // require that the service to fail initialization. All other
  426. // error will be logged by this routine. All returns from the
  427. // the FSD are treated as non-fatal.
  428. //
  429. DWORD
  430. AfpInitServerVolumes(
  431. VOID
  432. )
  433. {
  434. DWORD dwRetCode;
  435. LPWSTR lpwsValName, lpwsSrcIconPath, lpwsDstIconPath;
  436. DWORD dwMaxValNameLen;
  437. DWORD dwValNameBufSize;
  438. DWORD dwNumValues;
  439. DWORD dwMaxValueDataSize;
  440. DWORD dwIndex;
  441. DWORD dwType;
  442. DWORD dwBufSize;
  443. AFP_REQUEST_PACKET AfpRequestPkt;
  444. AFP_VOLUME_INFO VolumeInfo;
  445. LPBYTE lpbMultiSz;
  446. LPBYTE lpbFSDBuf;
  447. DWORD dwLength;
  448. DWORD dwCount;
  449. WCHAR wchServerIconFile[AFPSERVER_VOLUME_ICON_FILE_SIZE] = AFPSERVER_VOLUME_ICON_FILE;
  450. BOOLEAN fCopiedIcon;
  451. DWORD dwLastDstCharIndex;
  452. // Find out the size of the largest data value and the largest
  453. // value name.
  454. //
  455. if ( dwRetCode = AfpRegGetKeyInfo( AfpGlobals.hkeyVolumesList,
  456. &dwMaxValNameLen,
  457. &dwNumValues,
  458. &dwMaxValueDataSize
  459. ))
  460. return( dwRetCode );
  461. // If there are no volumes to add then simply return
  462. //
  463. if ( dwNumValues == 0 )
  464. return( NO_ERROR );
  465. if (( lpwsValName = (LPWSTR)LocalAlloc( LPTR, dwMaxValNameLen ) ) == NULL )
  466. return( ERROR_NOT_ENOUGH_MEMORY );
  467. if ((lpbMultiSz = (LPBYTE)LocalAlloc( LPTR, dwMaxValueDataSize )) == NULL ){
  468. LocalFree( lpwsValName );
  469. return( ERROR_NOT_ENOUGH_MEMORY );
  470. }
  471. if (( lpwsSrcIconPath = (LPWSTR)LocalAlloc( LPTR, (MAX_PATH+1) * sizeof(WCHAR) ) ) == NULL )
  472. {
  473. LocalFree( lpwsValName );
  474. LocalFree( lpbMultiSz );
  475. return( ERROR_NOT_ENOUGH_MEMORY );
  476. }
  477. if (( lpwsDstIconPath = (LPWSTR)LocalAlloc( LPTR, (MAX_PATH +
  478. AFPSERVER_VOLUME_ICON_FILE_SIZE + 1 +
  479. (sizeof(AFPSERVER_RESOURCE_STREAM)/sizeof(WCHAR))) *
  480. sizeof(WCHAR)) ) == NULL )
  481. {
  482. LocalFree( lpwsValName );
  483. LocalFree( lpbMultiSz );
  484. LocalFree( lpwsSrcIconPath );
  485. return( ERROR_NOT_ENOUGH_MEMORY );
  486. }
  487. // Construct a path to the NTSFM volume custom icon
  488. //
  489. *lpwsSrcIconPath = 0;
  490. if ( GetSystemDirectory( lpwsSrcIconPath, MAX_PATH+1 ))
  491. {
  492. wcscat( lpwsSrcIconPath, AFP_DEF_VOLICON_SRCNAME );
  493. }
  494. else
  495. {
  496. LocalFree( lpwsValName );
  497. LocalFree( lpbMultiSz );
  498. LocalFree( lpwsSrcIconPath );
  499. LocalFree( lpwsDstIconPath );
  500. return( GetLastError() );
  501. }
  502. for ( dwIndex = 0,
  503. dwBufSize = dwMaxValueDataSize,
  504. dwValNameBufSize = dwMaxValNameLen;
  505. dwIndex < dwNumValues;
  506. dwIndex++,
  507. dwBufSize = dwMaxValueDataSize,
  508. dwValNameBufSize = dwMaxValNameLen ) {
  509. ZeroMemory( lpbMultiSz, dwBufSize );
  510. // Get the volume info from the registry in multi-sz form.
  511. //
  512. if ( dwRetCode = RegEnumValue( AfpGlobals.hkeyVolumesList,
  513. dwIndex,
  514. lpwsValName,
  515. &dwValNameBufSize,
  516. NULL,
  517. &dwType,
  518. lpbMultiSz,
  519. &dwBufSize
  520. ))
  521. break;
  522. // Parse the mult sz and extract info into volume info structure
  523. //
  524. if ( dwRetCode = AfpBufParseMultiSz(
  525. AFP_VOLUME_STRUCT,
  526. lpbMultiSz,
  527. (LPBYTE)&VolumeInfo ) ) {
  528. // If this volume contained invalid registry information then log
  529. // it and store the volume name in the list of invalid volumes.
  530. //
  531. AfpAddInvalidVolume( lpwsValName, NULL );
  532. AfpLogEvent( AFPLOG_INVALID_VOL_REG,1,&lpwsValName,
  533. dwRetCode, EVENTLOG_WARNING_TYPE );
  534. dwRetCode = NO_ERROR;
  535. continue;
  536. }
  537. // Insert the volume name viz. the valuename
  538. //
  539. VolumeInfo.afpvol_name = lpwsValName;
  540. // Validate the volume info structure
  541. //
  542. if ( !IsAfpVolumeInfoValid( AFP_VALIDATE_ALL_FIELDS, &VolumeInfo ) ) {
  543. // If this volume contained invalid registry information then log
  544. // it and store the volume name in the list of invalid volumes.
  545. //
  546. AfpAddInvalidVolume( lpwsValName, NULL );
  547. AfpLogEvent( AFPLOG_INVALID_VOL_REG,1,&lpwsValName,
  548. dwRetCode, EVENTLOG_WARNING_TYPE );
  549. dwRetCode = NO_ERROR;
  550. continue;
  551. }
  552. // If there is a password then decrypt it
  553. //
  554. if ( VolumeInfo.afpvol_password != (LPWSTR)NULL ){
  555. dwLength = STRLEN( VolumeInfo.afpvol_password );
  556. for ( dwCount = 0; dwCount < dwLength; dwCount++ )
  557. VolumeInfo.afpvol_password[dwCount] ^= 0xF000;
  558. }
  559. //
  560. // Construct a path to the destination volume "Icon<0D>" file
  561. //
  562. fCopiedIcon = FALSE;
  563. wcscpy( lpwsDstIconPath, VolumeInfo.afpvol_path );
  564. if (lpwsDstIconPath[wcslen(lpwsDstIconPath) - 1] != TEXT('\\'))
  565. {
  566. wcscat( lpwsDstIconPath, TEXT("\\") );
  567. }
  568. wcscat( lpwsDstIconPath, wchServerIconFile );
  569. // Keep track of end of name without the resource fork tacked on
  570. //
  571. dwLastDstCharIndex = wcslen(lpwsDstIconPath);
  572. wcscat( lpwsDstIconPath, AFPSERVER_RESOURCE_STREAM );
  573. // Copy the icon file to the root of the volume (do not overwrite)
  574. //
  575. if ((fCopiedIcon = (BOOLEAN)CopyFile( lpwsSrcIconPath, lpwsDstIconPath, TRUE )) ||
  576. (GetLastError() == ERROR_FILE_EXISTS))
  577. {
  578. VolumeInfo.afpvol_props_mask |= AFP_VOLUME_HAS_CUSTOM_ICON;
  579. // Make sure the file is hidden
  580. SetFileAttributes( lpwsDstIconPath,
  581. FILE_ATTRIBUTE_HIDDEN |
  582. FILE_ATTRIBUTE_ARCHIVE );
  583. }
  584. // Make this a self relative buffer
  585. //
  586. if ( dwRetCode = AfpBufMakeFSDRequest(
  587. (LPBYTE)&VolumeInfo,
  588. 0,
  589. AFP_VOLUME_STRUCT,
  590. &lpbFSDBuf,
  591. &dwBufSize
  592. ))
  593. break;
  594. // Initialize the FSD with this volume
  595. //
  596. AfpRequestPkt.dwRequestCode = OP_VOLUME_ADD;
  597. AfpRequestPkt.dwApiType = AFP_API_TYPE_ADD;
  598. AfpRequestPkt.Type.Add.pInputBuf = lpbFSDBuf;
  599. AfpRequestPkt.Type.Add.cbInputBufSize = dwBufSize;
  600. dwRetCode = AfpServerIOCtrl( &AfpRequestPkt );
  601. if ( dwRetCode ) {
  602. // If this volume could not be added by the FSD then we errorlog
  603. // this and insert this volume into the list of invalid volumes.
  604. //
  605. AfpAddInvalidVolume( lpwsValName, VolumeInfo.afpvol_path );
  606. AfpLogEvent( AFPLOG_CANT_ADD_VOL, 1, &lpwsValName,
  607. dwRetCode, EVENTLOG_WARNING_TYPE );
  608. dwRetCode = NO_ERROR;
  609. // Delete the icon file we just copied if the volume add failed
  610. //
  611. if ( fCopiedIcon )
  612. {
  613. // Truncate the resource fork name so we delete the whole file
  614. lpwsDstIconPath[dwLastDstCharIndex] = 0;
  615. DeleteFile( lpwsDstIconPath );
  616. }
  617. }
  618. LocalFree( lpbFSDBuf );
  619. }
  620. LocalFree( lpwsValName );
  621. LocalFree( lpbMultiSz );
  622. LocalFree( lpwsSrcIconPath );
  623. LocalFree( lpwsDstIconPath );
  624. return( dwRetCode );
  625. }
  626. //**
  627. //
  628. // Call: AfpInitETCMaps
  629. //
  630. // Returns: NO_ERROR success
  631. // non-zero returns from the IOCTL
  632. // non-zero returns from the AfpRegXXX apis.
  633. //
  634. //
  635. // Description: This routine will read in all the type/creators and extensions
  636. // from the registry and store them in a cache. It will then
  637. // create a list of mappings from the cache and then IOCTL the
  638. // the FSD to add them. If the default is not in the registry,
  639. // a hardcoded one is used. All non-zero returns from this
  640. // routine are fatal. All non-fatal errors will be logged.
  641. //
  642. //
  643. DWORD
  644. AfpInitETCMaps(
  645. VOID
  646. )
  647. {
  648. DWORD dwRetCode;
  649. AFP_REQUEST_PACKET AfpSrp;
  650. AFP_EXTENSION DefExtension;
  651. AFP_TYPE_CREATOR DefTypeCreator;
  652. BYTE bDefaultETC[sizeof(ETCMAPINFO2)+sizeof(SETINFOREQPKT)];
  653. PAFP_TYPE_CREATOR pTypeCreator;
  654. DWORD dwNumTypeCreators;
  655. AFP_TYPE_CREATOR AfpTypeCreatorKey;
  656. // Get all type-creators from the registry and store them in a global cache.
  657. //
  658. if ( dwRetCode = AfpRegTypeCreatorEnum() )
  659. return( dwRetCode );
  660. // Get all extensions from the registry and store them in a global cache.
  661. //
  662. if ( dwRetCode = AfpRegExtensionEnum() )
  663. return( dwRetCode );
  664. // If there are no mappings do not IOCTL.
  665. //
  666. if ( AfpGlobals.AfpETCMapInfo.afpetc_num_extensions > 0 ) {
  667. // IOCTL the FSD to Add these mappings
  668. //
  669. AfpSrp.dwRequestCode = OP_SERVER_ADD_ETC;
  670. AfpSrp.dwApiType = AFP_API_TYPE_ADD;
  671. // Make a buffer with the type/creator mappings in the form as required
  672. // by the FSD
  673. //
  674. if ( dwRetCode = AfpBufMakeFSDETCMappings(
  675. (PSRVETCPKT*)&(AfpSrp.Type.Add.pInputBuf),
  676. &(AfpSrp.Type.Add.cbInputBufSize) ) )
  677. return( dwRetCode );
  678. if ( AfpSrp.Type.Add.cbInputBufSize > 0 ) {
  679. dwRetCode = AfpServerIOCtrl( &AfpSrp );
  680. LocalFree( AfpSrp.Type.Add.pInputBuf );
  681. if ( dwRetCode )
  682. return( dwRetCode );
  683. }
  684. else
  685. LocalFree( AfpSrp.Type.Add.pInputBuf );
  686. }
  687. // Check to see if the default type/creator is in the registry
  688. //
  689. AfpTypeCreatorKey.afptc_id = AFP_DEF_TCID;
  690. dwNumTypeCreators = AfpGlobals.AfpETCMapInfo.afpetc_num_type_creators;
  691. pTypeCreator = _lfind( &AfpTypeCreatorKey,
  692. AfpGlobals.AfpETCMapInfo.afpetc_type_creator,
  693. (unsigned int *)&dwNumTypeCreators,
  694. sizeof(AFP_TYPE_CREATOR),
  695. AfpLCompareTypeCreator );
  696. // If the default is not in the registry use the hard-coded defaults.
  697. //
  698. if ( pTypeCreator == NULL ) {
  699. STRCPY( DefTypeCreator.afptc_type, AFP_DEF_TYPE );
  700. STRCPY( DefTypeCreator.afptc_creator, AFP_DEF_CREATOR );
  701. STRCPY( DefTypeCreator.afptc_comment, AfpGlobals.wchDefTCComment );
  702. DefTypeCreator.afptc_id = AFP_DEF_TCID;
  703. }
  704. else
  705. DefTypeCreator = *pTypeCreator;
  706. ZeroMemory( (LPBYTE)(DefExtension.afpe_extension),
  707. AFP_FIELD_SIZE( AFP_EXTENSION, afpe_extension) );
  708. STRCPY( DefExtension.afpe_extension, AFP_DEF_EXTENSION_W );
  709. AfpBufCopyFSDETCMapInfo( &DefTypeCreator,
  710. &DefExtension,
  711. (PETCMAPINFO2)(bDefaultETC+sizeof(SETINFOREQPKT)));
  712. // IOCTL the FSD to set the default
  713. //
  714. AfpSrp.dwRequestCode = OP_SERVER_SET_ETC;
  715. AfpSrp.dwApiType = AFP_API_TYPE_SETINFO;
  716. AfpSrp.Type.SetInfo.pInputBuf = bDefaultETC;
  717. AfpSrp.Type.SetInfo.cbInputBufSize = sizeof( bDefaultETC );
  718. if ( dwRetCode = AfpServerIOCtrl( &AfpSrp ) )
  719. return( dwRetCode );
  720. // If the default was not in the cache, add it now.
  721. //
  722. if ( pTypeCreator == NULL ) {
  723. PAFP_TYPE_CREATOR pTmpTypeCreator = NULL;
  724. // Grow the cache size by one entry.
  725. //
  726. pTypeCreator = AfpGlobals.AfpETCMapInfo.afpetc_type_creator;
  727. dwNumTypeCreators = AfpGlobals.AfpETCMapInfo.afpetc_num_type_creators;
  728. pTmpTypeCreator = (PAFP_TYPE_CREATOR)LocalReAlloc(
  729. pTypeCreator,
  730. (dwNumTypeCreators+1)*sizeof(AFP_TYPE_CREATOR),
  731. LMEM_MOVEABLE );
  732. if ( pTmpTypeCreator == NULL )
  733. {
  734. return( ERROR_NOT_ENOUGH_MEMORY );
  735. }
  736. pTypeCreator = pTmpTypeCreator;
  737. pTypeCreator[dwNumTypeCreators++] = DefTypeCreator;
  738. AfpGlobals.AfpETCMapInfo.afpetc_num_type_creators = dwNumTypeCreators;
  739. AfpGlobals.AfpETCMapInfo.afpetc_type_creator = pTypeCreator;
  740. // Sort the table
  741. //
  742. qsort( pTypeCreator,
  743. dwNumTypeCreators,
  744. sizeof(AFP_TYPE_CREATOR),
  745. AfpBCompareTypeCreator );
  746. }
  747. return( NO_ERROR );
  748. }
  749. //**
  750. //
  751. // Call: AfpInitServerIcons
  752. //
  753. // Returns: NO_ERROR - success
  754. // ERROR_NOT_ENOUGH_MEMORY
  755. // non-zero return codes from registry apis.
  756. //
  757. // Description: This procedure will read in an icon at a time from the
  758. // registry, and then register this icon with the server.
  759. // This procedure will only return fatal errors that will
  760. // require that the service fail initialization. All other
  761. // error will be logged by this routine. All returns from the
  762. // the FSD are treated as non-fatal.
  763. //
  764. //
  765. DWORD
  766. AfpInitServerIcons(
  767. VOID
  768. )
  769. {
  770. DWORD dwRetCode;
  771. LPWSTR lpwsValName;
  772. DWORD dwMaxValNameLen;
  773. DWORD dwNumValues;
  774. DWORD dwMaxValueDataSize;
  775. DWORD dwIndex;
  776. DWORD dwType;
  777. DWORD dwBufSize;
  778. DWORD dwValNameBufSize;
  779. AFP_REQUEST_PACKET AfpRequestPkt;
  780. LPBYTE lpbMultiSz;
  781. AFP_ICON_INFO IconInfo;
  782. // Find out the size of the largest data value and the largest
  783. // value name.
  784. //
  785. if ( dwRetCode = AfpRegGetKeyInfo( AfpGlobals.hkeyIcons,
  786. &dwMaxValNameLen,
  787. &dwNumValues,
  788. &dwMaxValueDataSize
  789. ))
  790. return( dwRetCode );
  791. // If there are no icons in the registry then simply return
  792. //
  793. if ( dwNumValues == 0 )
  794. return( NO_ERROR );
  795. if (( lpwsValName = (LPWSTR)LocalAlloc( LPTR, dwMaxValNameLen )) == NULL )
  796. return( ERROR_NOT_ENOUGH_MEMORY );
  797. if (( lpbMultiSz = (LPBYTE)LocalAlloc( LPTR, dwMaxValueDataSize))== NULL){
  798. LocalFree( lpwsValName );
  799. return( ERROR_NOT_ENOUGH_MEMORY );
  800. }
  801. for ( dwIndex = 0,
  802. dwBufSize = dwMaxValueDataSize,
  803. dwValNameBufSize = dwMaxValNameLen;
  804. dwIndex < dwNumValues;
  805. dwIndex++,
  806. dwBufSize = dwMaxValueDataSize,
  807. dwValNameBufSize = dwMaxValNameLen ) {
  808. ZeroMemory( lpbMultiSz, dwBufSize );
  809. // Get the icon from the registry.
  810. //
  811. if ( dwRetCode = RegEnumValue( AfpGlobals.hkeyIcons,
  812. dwIndex,
  813. lpwsValName,
  814. &dwValNameBufSize,
  815. NULL,
  816. &dwType,
  817. lpbMultiSz,
  818. &dwBufSize
  819. ))
  820. break;
  821. // Parse the mult sz and extract info into icon info structure
  822. //
  823. if ( dwRetCode = AfpBufParseMultiSz(
  824. AFP_ICON_STRUCT,
  825. lpbMultiSz,
  826. (LPBYTE)&IconInfo
  827. )) {
  828. AfpLogEvent( AFPLOG_CANT_ADD_ICON, 1, &lpwsValName,
  829. dwRetCode, EVENTLOG_WARNING_TYPE );
  830. dwRetCode = NO_ERROR;
  831. continue;
  832. }
  833. if ( dwRetCode = AfpBufUnicodeToNibble((LPWSTR)IconInfo.afpicon_data)){
  834. AfpLogEvent( AFPLOG_CANT_ADD_ICON, 1, &lpwsValName,
  835. dwRetCode, EVENTLOG_WARNING_TYPE );
  836. dwRetCode = NO_ERROR;
  837. continue;
  838. }
  839. // Validate the icon info structure
  840. //
  841. if ( !IsAfpIconValid( &IconInfo ) ) {
  842. AfpLogEvent( AFPLOG_CANT_ADD_ICON, 1, &lpwsValName,
  843. dwRetCode, EVENTLOG_WARNING_TYPE );
  844. dwRetCode = NO_ERROR;
  845. continue;
  846. }
  847. // Copy the icon info into an FSD icon structure.
  848. // NOTE: Re-use lpbMultiSz to store the FSD Icon structure. We know
  849. // it is big enough, because the FSD icon structure HAS to be
  850. // smaller than the MultiSz that contains the same information.
  851. //
  852. AfpBufMakeFSDIcon( &IconInfo, lpbMultiSz, &dwBufSize );
  853. // Initialize the FSD with this icon
  854. //
  855. AfpRequestPkt.dwRequestCode = OP_SERVER_ADD_ICON;
  856. AfpRequestPkt.dwApiType = AFP_API_TYPE_ADD;
  857. AfpRequestPkt.Type.Add.pInputBuf = lpbMultiSz;
  858. AfpRequestPkt.Type.Add.cbInputBufSize = dwBufSize;
  859. if ( dwRetCode = AfpServerIOCtrl( &AfpRequestPkt ) ) {
  860. AfpLogEvent( AFPLOG_CANT_ADD_ICON, 1, &lpwsValName,
  861. dwRetCode, EVENTLOG_WARNING_TYPE );
  862. dwRetCode = NO_ERROR;
  863. continue;
  864. }
  865. }
  866. LocalFree( lpwsValName );
  867. LocalFree( lpbMultiSz );
  868. return( dwRetCode );
  869. }
  870. //**
  871. //
  872. // Call: AfpInitRPC
  873. //
  874. // Returns: NO_ERROR - success
  875. // ERROR_NOT_ENOUGH_MEMORY
  876. // nonzero returns from RPC APIs
  877. // RpcServerRegisterIf()
  878. // RpcServerUseProtseqEp()
  879. //
  880. // Description: Starts an RPC Server, adds the address (or port/pipe),
  881. // and adds the interface (dispatch table).
  882. //
  883. DWORD
  884. AfpInitRPC( VOID )
  885. {
  886. RPC_STATUS RpcStatus;
  887. LPWSTR lpwsEndpoint = NULL;
  888. BOOL Bool;
  889. // We need to concatenate \pipe\ to the front of the interface name.
  890. //
  891. lpwsEndpoint = (LPWSTR)LocalAlloc( LPTR, sizeof(NT_PIPE_PREFIX) +
  892. ((STRLEN(AFP_SERVICE_NAME)+1)*sizeof(WCHAR)));
  893. if ( lpwsEndpoint == NULL)
  894. return( ERROR_NOT_ENOUGH_MEMORY );
  895. STRCPY( lpwsEndpoint, NT_PIPE_PREFIX );
  896. STRCAT( lpwsEndpoint, AFP_SERVICE_NAME );
  897. // Ignore the second argument for now.
  898. //
  899. RpcStatus = RpcServerUseProtseqEpW( TEXT("ncacn_np"),
  900. 10,
  901. lpwsEndpoint,
  902. NULL );
  903. if ( RpcStatus != RPC_S_OK )
  904. {
  905. LocalFree( lpwsEndpoint );
  906. return( I_RpcMapWin32Status( RpcStatus ) );
  907. }
  908. RpcStatus = RpcServerRegisterIfEx( afpsvc_v0_0_s_ifspec,
  909. 0,
  910. 0,
  911. RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
  912. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  913. AfpRpcSecurityCallback );
  914. LocalFree( lpwsEndpoint );
  915. if ( RpcStatus == RPC_S_OK )
  916. return( NO_ERROR );
  917. else
  918. return( I_RpcMapWin32Status( RpcStatus ) );
  919. }
  920. //**
  921. //
  922. // Call: AfpTerminateRPC
  923. //
  924. // Returns: none
  925. //
  926. // Description: Deletes the interface.
  927. //
  928. VOID
  929. AfpTerminateRPC(
  930. VOID
  931. )
  932. {
  933. RPC_STATUS RpcStatus;
  934. if ( AfpGlobals.dwServerState & AFPSTATE_RPC_STARTED )
  935. {
  936. RpcStatus = RpcServerUnregisterIf( afpsvc_v0_0_s_ifspec, 0, 0 );
  937. if (RpcStatus != RPC_S_OK)
  938. {
  939. AFP_PRINT(("RpcServerUnregisterIf failed %ld\n", I_RpcMapWin32Status( RpcStatus )));
  940. }
  941. }
  942. return;
  943. }
  944. //**
  945. //
  946. // Call: AfpIniLsa
  947. //
  948. // Returns: none.
  949. //
  950. // Description: This procedure will register our process with LSA, needed for
  951. // change-password
  952. //
  953. VOID
  954. AfpIniLsa(
  955. VOID
  956. )
  957. {
  958. NTSTATUS ntstatus;
  959. STRING LsaName;
  960. LSA_OPERATIONAL_MODE SecurityMode;
  961. //
  962. // register with Lsa as a logon process
  963. //
  964. RtlInitString(&LsaName, LOGON_PROCESS_NAME);
  965. ntstatus = LsaRegisterLogonProcess(&LsaName, &SfmLsaHandle, &SecurityMode);
  966. if (ntstatus != STATUS_SUCCESS)
  967. {
  968. SfmLsaHandle = NULL;
  969. return;
  970. }
  971. //
  972. // call Lsa to get the MSV1_0's pkg id, which we need during logon
  973. //
  974. RtlInitString(&LsaName, MSV1_0_PACKAGE_NAME);
  975. ntstatus = LsaLookupAuthenticationPackage(SfmLsaHandle, &LsaName, &SfmAuthPkgId);
  976. if (ntstatus != STATUS_SUCCESS)
  977. {
  978. LsaDeregisterLogonProcess( SfmLsaHandle );
  979. SfmLsaHandle = NULL;
  980. return;
  981. }
  982. return;
  983. }
  984. BOOL
  985. IsAfpGuestAccountEnabled(
  986. VOID
  987. )
  988. {
  989. NTSTATUS rc;
  990. LSA_HANDLE hLsa;
  991. PPOLICY_ACCOUNT_DOMAIN_INFO pAcctDomainInfo;
  992. SECURITY_QUALITY_OF_SERVICE QOS;
  993. OBJECT_ATTRIBUTES ObjAttribs;
  994. NTSTATUS status;
  995. SAM_HANDLE SamHandle;
  996. SAM_HANDLE DomainHandle;
  997. PUSER_ACCOUNT_INFORMATION UserAccount = NULL;
  998. BOOLEAN fGuestEnabled;
  999. SAMPR_HANDLE GuestAcctHandle;
  1000. // for now
  1001. fGuestEnabled = FALSE;
  1002. //
  1003. // Open the LSA and obtain a handle to it.
  1004. //
  1005. QOS.Length = sizeof(QOS);
  1006. QOS.ImpersonationLevel = SecurityImpersonation;
  1007. QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1008. QOS.EffectiveOnly = FALSE;
  1009. InitializeObjectAttributes(&ObjAttribs, NULL, 0L, NULL, NULL);
  1010. ObjAttribs.SecurityQualityOfService = &QOS;
  1011. status = LsaOpenPolicy(NULL,
  1012. &ObjAttribs,
  1013. POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES,
  1014. &hLsa);
  1015. if (!NT_SUCCESS(status))
  1016. {
  1017. AFP_PRINT(("LsaOpenPolicy failed %lx\n",status));
  1018. return(fGuestEnabled);
  1019. }
  1020. //
  1021. // get the Domain Sid for the local domain: we'll need it very shortly
  1022. //
  1023. rc = LsaQueryInformationPolicy(hLsa,
  1024. PolicyAccountDomainInformation,
  1025. (PVOID) &pAcctDomainInfo);
  1026. if (!NT_SUCCESS(rc))
  1027. {
  1028. AFP_PRINT(("InitLSA: LsaQueryInfo... failed (%lx)\n",rc));
  1029. LsaClose(hLsa);
  1030. return(fGuestEnabled);
  1031. }
  1032. InitializeObjectAttributes(&ObjAttribs, NULL, 0L, NULL, NULL);
  1033. status = SamConnect(NULL, &SamHandle, MAXIMUM_ALLOWED, &ObjAttribs);
  1034. if (!NT_SUCCESS(status))
  1035. {
  1036. AFP_PRINT(("SamConnect failed %lx\n",status));
  1037. LsaFreeMemory(pAcctDomainInfo);
  1038. LsaClose(hLsa);
  1039. return(fGuestEnabled);
  1040. }
  1041. status = SamOpenDomain(
  1042. SamHandle,
  1043. MAXIMUM_ALLOWED,
  1044. pAcctDomainInfo->DomainSid,
  1045. &DomainHandle);
  1046. LsaFreeMemory(pAcctDomainInfo);
  1047. LsaClose(hLsa);
  1048. if (!NT_SUCCESS(status))
  1049. {
  1050. AFP_PRINT(("SamOpenDomain failed %lx\n",status));
  1051. SamCloseHandle(SamHandle);
  1052. return(fGuestEnabled);
  1053. }
  1054. status = SamOpenUser(
  1055. DomainHandle,
  1056. MAXIMUM_ALLOWED,
  1057. DOMAIN_USER_RID_GUEST,
  1058. &GuestAcctHandle);
  1059. if (!NT_SUCCESS(status))
  1060. {
  1061. AFP_PRINT(("SamOpenUser failed %lx\n",status));
  1062. SamCloseHandle(SamHandle);
  1063. return(fGuestEnabled);
  1064. }
  1065. status = SamQueryInformationUser(
  1066. GuestAcctHandle,
  1067. UserAccountInformation,
  1068. (PVOID *) &UserAccount );
  1069. if (!NT_SUCCESS(status))
  1070. {
  1071. AFP_PRINT(("SamQueryInformationUser failed %lx\n",status));
  1072. SamCloseHandle(SamHandle);
  1073. return(fGuestEnabled);
  1074. }
  1075. //
  1076. // now, see if the guest account is enabled.
  1077. //
  1078. if (!(UserAccount->UserAccountControl & USER_ACCOUNT_DISABLED))
  1079. {
  1080. fGuestEnabled = TRUE;
  1081. }
  1082. SamFreeMemory(UserAccount);
  1083. SamCloseHandle(GuestAcctHandle);
  1084. SamCloseHandle(SamHandle);
  1085. return(fGuestEnabled);
  1086. }