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

943 lines
26 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1999
  5. //
  6. // File: FatNot.cxx
  7. //
  8. // Contents: Downlevel notification.
  9. //
  10. // Classes: CGenericNotify
  11. //
  12. // History: 2-23-96 KyleP Lifed from DLNotify.?xx
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <fatnot.hxx>
  18. #include <pathpars.hxx>
  19. #include <imprsnat.hxx>
  20. #include <catalog.hxx>
  21. #include <cicat.hxx>
  22. #include <ciregkey.hxx>
  23. #include <cievtmsg.h>
  24. #include <eventlog.hxx>
  25. #include <lm.h>
  26. //+---------------------------------------------------------------------------
  27. //
  28. // Class: CRemoteNotifications
  29. //
  30. // Purpose: A class to impersonate and enable notifications for remote
  31. // shares.
  32. //
  33. // History: 7-15-96 srikants Created
  34. //
  35. // Notes: When there are multiple alternatives possible for a remote
  36. // share, we have to use the one that allows access to remote
  37. // share (if there is one). There may be some which don't allow
  38. // the required access and we should skip those.
  39. //
  40. //----------------------------------------------------------------------------
  41. class CRemoteNotifications : public PImpersonatedWorkItem
  42. {
  43. public:
  44. CRemoteNotifications( WCHAR const * pwszPath,
  45. CGenericNotify & notify,
  46. OBJECT_ATTRIBUTES & objAttr )
  47. : PImpersonatedWorkItem( pwszPath ),
  48. _notify(notify),
  49. _objAttr(objAttr),
  50. _status(STATUS_SUCCESS)
  51. {
  52. }
  53. NTSTATUS OpenAndStart( CImpersonateRemoteAccess & remoteAccess );
  54. virtual BOOL DoIt();
  55. private:
  56. CGenericNotify & _notify;
  57. OBJECT_ATTRIBUTES & _objAttr;
  58. NTSTATUS _status;
  59. };
  60. //+---------------------------------------------------------------------------
  61. //
  62. // Member: CRemoteNotifications::DoIt
  63. //
  64. // Synopsis: The virtual method that does the work under an impersonated
  65. // context.
  66. //
  67. // Returns: TRUE if successful;
  68. // FALSE o/w
  69. //
  70. // History: 7-15-96 srikants Created
  71. //
  72. //----------------------------------------------------------------------------
  73. BOOL CRemoteNotifications::DoIt()
  74. {
  75. _status = _notify.OpenDirectory( _objAttr );
  76. if ( IsRetryableError( _status ) )
  77. {
  78. //
  79. // We should attempt the open under a different impersonation
  80. // if possible.
  81. //
  82. return FALSE;
  83. }
  84. if ( NT_ERROR(_status) )
  85. THROW( CException( _status ) );
  86. //
  87. // Now, enable the notifications.
  88. //
  89. _notify.StartNotification( &_status ); // already impersonated
  90. if ( NT_ERROR(_status) )
  91. {
  92. _notify.CloseDirectory();
  93. if ( IsRetryableError(_status) )
  94. return FALSE;
  95. THROW( CException( _status ) );
  96. }
  97. //
  98. // Successfully enabled notifications.
  99. //
  100. return TRUE;
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Member: CRemoteNotifications::OpenAndStart
  105. //
  106. // Synopsis: Opens and start notifications for the remote root by trying
  107. // various impersonation contexts if necessary.
  108. //
  109. // Arguments: [remoteAccess] - The object to use for remote access.
  110. //
  111. // Returns: NTSTATUS of the whole operation.
  112. //
  113. // History: 7-15-96 srikants Created
  114. //
  115. //----------------------------------------------------------------------------
  116. NTSTATUS
  117. CRemoteNotifications::OpenAndStart( CImpersonateRemoteAccess & remoteAccess )
  118. {
  119. TRY
  120. {
  121. ImpersonateAndDoWork( remoteAccess );
  122. }
  123. CATCH( CException,e )
  124. {
  125. vqDebugOut(( DEB_ERROR, "OpenAndStart failed with error (0x%X)\n",
  126. e.GetErrorCode() ));
  127. _status = e.GetErrorCode();
  128. }
  129. END_CATCH
  130. return _status;
  131. }
  132. //+---------------------------------------------------------------------------
  133. //
  134. // Member: CGenericNotify::CGenericNotify
  135. //
  136. // Synopsis: Constructor of the single scope notification object CGenericNotify.
  137. //
  138. // Arguments: [wcsScope] -- Scope to watch
  139. // [cwcScope] -- Size in chars of [wcsScope]
  140. // [fDeep] -- Set to TRUE if deep notifications are enabled.
  141. //
  142. // History: 1-17-96 srikants Created
  143. //
  144. //----------------------------------------------------------------------------
  145. CGenericNotify::CGenericNotify( PCatalog *pCat,
  146. WCHAR const * wcsScope,
  147. unsigned cwcScope,
  148. BOOL fDeep,
  149. BOOL fLogEvents )
  150. : _refCount(1),
  151. _pCat( pCat ),
  152. _fNotifyActive(FALSE),
  153. _fRemoteDrive(FALSE),
  154. _cwcScope(cwcScope),
  155. _fDeep(fDeep),
  156. _fLogEvents(fLogEvents),
  157. _fAbort(FALSE),
  158. _hNotify(0),
  159. _pbBuffer(0)
  160. {
  161. if ( cwcScope >= MAX_PATH )
  162. {
  163. THROW( CException( STATUS_INVALID_PARAMETER ) );
  164. }
  165. RtlCopyMemory( _wcsScope, wcsScope, cwcScope * sizeof(WCHAR) );
  166. _wcsScope[cwcScope] = 0;
  167. CDoubleLink::Close();
  168. //
  169. // Bigger buffer for local scopes.
  170. //
  171. _fRemoteDrive = !IsFixedDrive( _wcsScope, _cwcScope );
  172. if ( _fRemoteDrive )
  173. _cbBuffer = CB_REMOTENOTIFYBUFFER;
  174. else
  175. _cbBuffer = CB_NOTIFYBUFFER;
  176. //
  177. // Client should call EnableNotification() in ctor. Delay allocating
  178. // the buffer in case this is a USN volume and no buffer is needed.
  179. //
  180. }
  181. //+---------------------------------------------------------------------------
  182. //
  183. // Member: CGenericNotify::~CGenericNotify
  184. //
  185. // Synopsis: ~dtor . Disables further notifications and frees up
  186. // memory.
  187. //
  188. // History: 1-17-96 srikants Created
  189. //
  190. // Notes:
  191. //
  192. //----------------------------------------------------------------------------
  193. CGenericNotify::~CGenericNotify()
  194. {
  195. Win4Assert( 0 == _refCount );
  196. Win4Assert( IsSingle() );
  197. Win4Assert( 0 == _hNotify );
  198. delete [] _pbBuffer;
  199. }
  200. //+---------------------------------------------------------------------------
  201. //
  202. // Member: CGenericNotify::OpenDirectory
  203. //
  204. // Synopsis: Opens a remote directory and uses the given object attributes.
  205. //
  206. // Arguments: [ObjectAttr] -
  207. //
  208. // Returns: STATUS of the operation.
  209. //
  210. // History: 7-15-96 srikants Created
  211. //
  212. //----------------------------------------------------------------------------
  213. NTSTATUS
  214. CGenericNotify::OpenDirectory( OBJECT_ATTRIBUTES & ObjectAttr )
  215. {
  216. BOOL fSuccess = TRUE;
  217. ULONG cSkip = 0;
  218. NTSTATUS Status = STATUS_SUCCESS;
  219. IO_STATUS_BLOCK IoStatus;
  220. Status = NtOpenFile( &_hNotify, // Handle
  221. FILE_LIST_DIRECTORY | SYNCHRONIZE, // Access
  222. &ObjectAttr, // Object Attributes
  223. &IoStatus, // I/O Status block
  224. FILE_SHARE_READ |
  225. FILE_SHARE_WRITE |
  226. FILE_SHARE_DELETE,
  227. FILE_DIRECTORY_FILE ); // Flags
  228. if ( NT_ERROR(Status) )
  229. _hNotify = 0;
  230. return Status;
  231. }
  232. //+---------------------------------------------------------------------------
  233. //
  234. // Member: CGenericNotify::CloseDirectory
  235. //
  236. // Synopsis: Closes the directory handle if open and sets it to 0.
  237. //
  238. // History: 7-15-96 srikants Created
  239. //
  240. //----------------------------------------------------------------------------
  241. void CGenericNotify::CloseDirectory()
  242. {
  243. if ( 0 != _hNotify )
  244. {
  245. NtClose( _hNotify );
  246. _hNotify = 0;
  247. }
  248. }
  249. //+---------------------------------------------------------------------------
  250. //
  251. // Member: CGenericNotify::EnableNotification
  252. //
  253. // Synopsis: Enables notifications for the current scope.
  254. //
  255. // History: 1-17-96 srikants Created
  256. //
  257. //----------------------------------------------------------------------------
  258. void CGenericNotify::EnableNotification()
  259. {
  260. vqDebugOut(( DEB_ITRACE, "Enable notification for scope %ws this=0x%x\n", _wcsScope, this ));
  261. if ( 0 == _pbBuffer )
  262. _pbBuffer = new BYTE [_cbBuffer];
  263. //
  264. // Open file
  265. //
  266. NTSTATUS Status;
  267. UNICODE_STRING uScope;
  268. if ( !RtlDosPathNameToNtPathName_U( _wcsScope,
  269. &uScope,
  270. 0,
  271. 0 ) )
  272. {
  273. vqDebugOut(( DEB_ERROR, "Error converting %ws to Nt path\n", _wcsScope ));
  274. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  275. }
  276. XRtlHeapMem xScopeBuf( uScope.Buffer );
  277. OBJECT_ATTRIBUTES ObjectAttr;
  278. InitializeObjectAttributes( &ObjectAttr, // Structure
  279. &uScope, // Name
  280. OBJ_CASE_INSENSITIVE, // Attributes
  281. 0, // Root
  282. 0 ); // Security
  283. CImpersonateRemoteAccess remoteAccess( GetCatalog()->GetImpersonationTokenCache() );
  284. CRemoteNotifications remoteNotify( _wcsScope, *this, ObjectAttr );
  285. if ( _fRemoteDrive )
  286. {
  287. //
  288. // Check if remote notifications are disabled.
  289. //
  290. if ( (GetCatalog()->GetRegParams())->GetCiCatalogFlags() &
  291. CI_FLAGS_NO_REMOTE_NOTIFY )
  292. {
  293. vqDebugOut(( DEB_WARN,
  294. "Not enabling remote notifications because it is disabled in registry\n" ));
  295. return;
  296. }
  297. //
  298. // Check if the remote drive is a DFS share. If so, don't try
  299. // to enabled notifications on the share. We have to just periodically
  300. // scan for changed documents.
  301. //
  302. if ( IsDfsShare( _wcsScope, _cwcScope ) )
  303. {
  304. vqDebugOut(( DEB_WARN, "Not enabling notifications for DFS Share (%ws) \n",
  305. _wcsScope ));
  306. LogDfsShare();
  307. return;
  308. }
  309. Status = remoteNotify.OpenAndStart( remoteAccess );
  310. }
  311. else
  312. {
  313. //
  314. // Check if local notifications are disabled.
  315. //
  316. if ( (GetCatalog()->GetRegParams())->GetCiCatalogFlags() &
  317. CI_FLAGS_NO_LOCAL_NOTIFY )
  318. {
  319. vqDebugOut(( DEB_WARN,
  320. "Not enabling local notifications because it is disabled in registry\n" ));
  321. return;
  322. }
  323. Status = OpenDirectory( ObjectAttr );
  324. if ( NT_ERROR( Status ) )
  325. {
  326. vqDebugOut(( DEB_ERROR,
  327. "Notification disabled. NtOpenFile( %ws ) returned 0x%lx\n",
  328. _wcsScope, Status ));
  329. _hNotify = 0;
  330. if ( _fLogEvents )
  331. LogNoNotifications( Status );
  332. return;
  333. }
  334. StartNotification( &Status );
  335. }
  336. if ( !_fNotifyActive && _fLogEvents )
  337. {
  338. LogNoNotifications( Status );
  339. }
  340. }
  341. //+---------------------------------------------------------------------------
  342. //
  343. // Member: CGenericNotify::DisableNotification
  344. //
  345. // Synopsis: Disables further notifications for this scope.
  346. //
  347. // History: 1-17-96 srikants Created
  348. //
  349. // Notes:
  350. //
  351. //----------------------------------------------------------------------------
  352. void CGenericNotify::DisableNotification()
  353. {
  354. vqDebugOut(( DEB_ITRACE, "Disable notification for scope %ws this=0x%x\n", _wcsScope, this ));
  355. if ( 0 != _hNotify )
  356. {
  357. NtClose( _hNotify );
  358. _hNotify = 0;
  359. }
  360. Release();
  361. }
  362. //+---------------------------------------------------------------------------
  363. //
  364. // Member: CGenericNotify::StartNotification
  365. //
  366. // Synopsis: Starts notifications by setting the APC for receiving
  367. // notifications. If successful, the object will be refcounted
  368. // and the status set to indicate that the operation is
  369. // successful.
  370. //
  371. // History: 1-17-96 srikants Created
  372. //
  373. // Notes: This must be called from within the lock of the notify manager.
  374. // If successful, the notify manager will also be
  375. // refcounted. This is because the APC depends upon the mutex
  376. // in the notify manager to be around when it is invoked.
  377. //
  378. //----------------------------------------------------------------------------
  379. void CGenericNotify::StartNotification( NTSTATUS * pStatus )
  380. {
  381. //
  382. // Set up query directory file.
  383. //
  384. NTSTATUS Status = STATUS_SUCCESS;
  385. DWORD dwFlags = GetNotifyFlags();
  386. Status = NtNotifyChangeDirectoryFile( _hNotify,
  387. 0,
  388. APC,
  389. this,
  390. &_iosNotify,
  391. _pbBuffer,
  392. _cbBuffer,
  393. dwFlags,
  394. (BYTE)_fDeep );
  395. if ( NT_ERROR(Status) )
  396. {
  397. vqDebugOut(( DEB_ERROR,
  398. "NtNotifyChangeDirectoryFile( %ws ) returned 0x%lx\n",
  399. _wcsScope, Status ));
  400. }
  401. else
  402. {
  403. _fNotifyActive = TRUE;
  404. AddRef();
  405. }
  406. if ( pStatus )
  407. *pStatus = Status;
  408. }
  409. //+---------------------------------------------------------------------------
  410. //
  411. // Member: CGenericNotify::AddRef
  412. //
  413. // History: 1-17-96 srikants Created
  414. //
  415. //----------------------------------------------------------------------------
  416. void CGenericNotify::AddRef()
  417. {
  418. InterlockedIncrement(&_refCount);
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Member: CGenericNotify::Release
  423. //
  424. // Synopsis: If the refcount goes to 0, the object will be deleted.
  425. //
  426. // History: 1-17-96 srikants Created
  427. //
  428. //----------------------------------------------------------------------------
  429. void CGenericNotify::Release()
  430. {
  431. Win4Assert( _refCount > 0 );
  432. if ( InterlockedDecrement(&_refCount) <= 0 )
  433. delete this;
  434. }
  435. //+---------------------------------------------------------------------------
  436. //
  437. // Member: CGenericNotify::AdjustForOverflow
  438. //
  439. // Synopsis: Increases the size of the notification buffer if it is not
  440. // a remote drive and if the current size is < the maximum.
  441. //
  442. // History: 2-27-96 srikants Created
  443. //
  444. // Notes:
  445. //
  446. //----------------------------------------------------------------------------
  447. void CGenericNotify::AdjustForOverflow()
  448. {
  449. if ( !_fRemoteDrive && CB_MAXSIZE > _cbBuffer )
  450. {
  451. unsigned cbNew = min( _cbBuffer + CB_DELTAINCR, CB_MAXSIZE );
  452. vqDebugOut(( DEB_ITRACE,
  453. "Resizing notification buffer from 0x%X to 0x%X bytes\n",
  454. _cbBuffer, cbNew ));
  455. BYTE * pbNew = new BYTE [cbNew];
  456. delete [] _pbBuffer;
  457. _pbBuffer = pbNew;
  458. _cbBuffer = cbNew;
  459. }
  460. }
  461. //+---------------------------------------------------------------------------
  462. //
  463. // Member: CGenericNotify::APC
  464. //
  465. // Synopsis: Asynchronous Procedure Call invoked by the system when there
  466. // is a change notification (or related error).
  467. //
  468. // Arguments: [ApcContext] - Pointer to "this"
  469. // [IoStatusBlock] -
  470. // [Reserved] -
  471. //
  472. // History: 1-17-96 srikants Created
  473. //
  474. // Notes:
  475. //
  476. //----------------------------------------------------------------------------
  477. void CGenericNotify::APC( void * ApcContext,
  478. IO_STATUS_BLOCK * IoStatusBlock,
  479. ULONG Reserved )
  480. {
  481. Win4Assert( 0 != ApcContext );
  482. CGenericNotify * pthis = (CGenericNotify *)ApcContext;
  483. NTSTATUS status = STATUS_SUCCESS;
  484. TRY
  485. {
  486. pthis->_fOverflow = FALSE;
  487. Win4Assert( &pthis->_iosNotify == IoStatusBlock );
  488. // DbgPrint( "notifications...\n" );
  489. if ( NT_ERROR( IoStatusBlock->Status ) )
  490. {
  491. if ( !pthis->_fAbort )
  492. {
  493. // DbgPrint( "Async notification for scope %ws received error 0x%x\n",
  494. // pthis->_wcsScope,
  495. // IoStatusBlock->Status );
  496. vqDebugOut(( DEB_ERROR,
  497. "Async notification for scope %ws received error 0x%x\n",
  498. pthis->_wcsScope,
  499. IoStatusBlock->Status ));
  500. vqDebugOut(( DEB_ITRACE, "CiNotification APC: ERROR 0x%x\n", pthis ));
  501. status = IoStatusBlock->Status;
  502. //
  503. // The I/O failed and it may be due to STATUS_DELETE_PENDING.
  504. // In any case, just close the handle so the directory is
  505. // freed for other apps.
  506. //
  507. pthis->CloseDirectory();
  508. }
  509. }
  510. else if ( IoStatusBlock->Status == STATUS_NOTIFY_CLEANUP )
  511. {
  512. vqDebugOut(( DEB_ITRACE, "CiNotification APC: CLOSE 0x%x\n", pthis ));
  513. }
  514. else
  515. {
  516. if ( IoStatusBlock->Status == STATUS_NOTIFY_ENUM_DIR )
  517. {
  518. // DbgPrint( "***** CiNotification LOST UPDATES for scope %ws *****\n",
  519. // pthis->_wcsScope );
  520. vqDebugOut(( DEB_WARN,
  521. "***** CiNotification LOST UPDATES for scope %ws *****\n",
  522. pthis->_wcsScope ));
  523. pthis->_fOverflow = TRUE;
  524. //
  525. // Let us adjust the size of the buffer if possible.
  526. //
  527. pthis->AdjustForOverflow();
  528. //
  529. // But call anyway. Client is responsible for checking ::BufferOverflow.
  530. //
  531. pthis->DoIt();
  532. }
  533. else
  534. {
  535. // .Information is the # of bytes written to the buffer.
  536. // This may be 0 even when .Status is STATUS_NOTIFY_ENUM_DIR,
  537. // and with certain builds of rdr2, STATUS_SUCCESS.
  538. if ( 0 == IoStatusBlock->Information &&
  539. 0 == IoStatusBlock->Status )
  540. {
  541. // BrianAn says NTFS won't do this, but rdr2 might
  542. vqDebugOut(( DEB_WARN,
  543. "CGenericNotify: invalid notification apc\n" ));
  544. // DbgPrint( "0 info and status block\n" );
  545. }
  546. #if 0
  547. if ( 0 != IoStatusBlock->Information )
  548. #endif
  549. {
  550. if ( !pthis->_fRemoteDrive )
  551. {
  552. pthis->DoIt();
  553. }
  554. else
  555. {
  556. //
  557. // Get sufficient impersonation context to get attributes on
  558. // the remote share. Then process the notifications.
  559. //
  560. CImpersonateRemoteAccess remote( pthis->GetCatalog()->GetImpersonationTokenCache() );
  561. CImpersonatedGetAttr getAttr( pthis->_wcsScope );
  562. getAttr.DoWork( remote );
  563. pthis->DoIt();
  564. }
  565. }
  566. }
  567. }
  568. }
  569. CATCH(CException, e)
  570. {
  571. //DbgPrint( "caught exception in notifications\n" );
  572. vqDebugOut(( DEB_ERROR,
  573. "CiNotification APC: CATCH 0x%x, iostatus: 0x%x, info: 0x%x\n",
  574. e.GetErrorCode(),
  575. IoStatusBlock->Status,
  576. IoStatusBlock->Information ));
  577. status = e.GetErrorCode();
  578. }
  579. END_CATCH;
  580. if ( STATUS_SUCCESS != status )
  581. {
  582. //DbgPrint( "clearing notify enabled\n" );
  583. pthis->ClearNotifyEnabled();
  584. if ( pthis->_fLogEvents )
  585. pthis->LogNotificationsFailed( status );
  586. }
  587. pthis->Release();
  588. } //APC
  589. //+---------------------------------------------------------------------------
  590. //
  591. // Member: CGenericNotify::IsFixedDrive, private
  592. //
  593. // Arguments: [wcsScope] -- Scope to check
  594. // [len] -- Length in chars of [wcsScope]
  595. //
  596. // Returns: TRUE if scope is for a fixed drive.
  597. //
  598. // History: 1-17-96 srikants Created
  599. //
  600. //----------------------------------------------------------------------------
  601. BOOL CGenericNotify::IsFixedDrive( WCHAR const * wcsScope, ULONG len )
  602. {
  603. CPathParser pathParser( wcsScope, len );
  604. if ( pathParser.IsUNCName() )
  605. return FALSE;
  606. WCHAR wDrive[MAX_PATH];
  607. ULONG cc=sizeof(wDrive)/sizeof(WCHAR);
  608. pathParser.GetFileName( wDrive, cc );
  609. UINT uType = GetDriveType( wDrive );
  610. return DRIVE_FIXED == uType;
  611. }
  612. //+---------------------------------------------------------------------------
  613. //
  614. // Function: CiNetShareGetInfo
  615. //
  616. // Synopsis: Calls NetShareGetInfo. Loads the library so we don't
  617. // link to netapi32.dll for the odd case of indexing remote
  618. // volumes. Also, don't cache the function pointer since
  619. // it's called so rarely.
  620. //
  621. // Arguments: Same as NetShareGetInfo
  622. //
  623. // Returns: Win32 / NetStatus error code
  624. //
  625. // History: 2-18-98 dlee Created
  626. //
  627. //----------------------------------------------------------------------------
  628. typedef NET_API_STATUS (NET_API_FUNCTION * NET_SHARE_GET_INFO_FUNC)(
  629. LPTSTR servername,
  630. LPTSTR netname,
  631. DWORD level,
  632. BYTE ** bufptr );
  633. NET_API_STATUS NET_API_FUNCTION CiNetShareGetInfo(
  634. LPTSTR servername,
  635. LPTSTR netname,
  636. DWORD level,
  637. BYTE ** bufptr )
  638. {
  639. HINSTANCE hLib = LoadLibrary( L"netapi32.dll" );
  640. if ( 0 == hLib )
  641. return GetLastError();
  642. NET_SHARE_GET_INFO_FUNC pfn = (NET_SHARE_GET_INFO_FUNC)
  643. GetProcAddress( hLib, "NetShareGetInfo" );
  644. if ( 0 == pfn )
  645. {
  646. FreeLibrary( hLib );
  647. return GetLastError();
  648. }
  649. NET_API_STATUS status = (*pfn)( servername, netname, level, bufptr );
  650. FreeLibrary( hLib );
  651. return status;
  652. } //CiNetShareGetInfo
  653. //+---------------------------------------------------------------------------
  654. //
  655. // Function: IsDfsShare
  656. //
  657. // Synopsis: Determines if the given UNC share is a DFS share.
  658. //
  659. // Arguments: [wcsScope] - scope
  660. // [len] - Length
  661. //
  662. // Returns: TRUE if it is a DFS share. FALSE o/w
  663. //
  664. // History: 6-23-96 srikants Created
  665. //
  666. //----------------------------------------------------------------------------
  667. BOOL CGenericNotify::IsDfsShare( WCHAR const * wcsScope, ULONG len )
  668. {
  669. CPathParser pathParser( wcsScope, len );
  670. if ( !pathParser.IsUNCName() )
  671. return FALSE;
  672. WCHAR wDrive[MAX_PATH];
  673. ULONG cc=sizeof(wDrive)/sizeof(WCHAR);
  674. pathParser.GetFileName( wDrive, cc );
  675. WCHAR * pwszServerName = wDrive;
  676. WCHAR * pwszShareName = 0;
  677. //
  678. // Locate the third backslash and replace it with a NULL char.
  679. //
  680. for ( unsigned i = 2; i < cc; i++ )
  681. {
  682. if ( wDrive[i] == L'\\' )
  683. {
  684. wDrive[i] = 0;
  685. pwszShareName = wDrive+i+1;
  686. break;
  687. }
  688. }
  689. Win4Assert( 0 != pwszShareName );
  690. //
  691. // Remove any trailing backslash in the share name.
  692. //
  693. i = wcslen( pwszShareName );
  694. if ( L'\\' == pwszShareName[i-1] )
  695. {
  696. pwszShareName[i-1] = 0;
  697. }
  698. BOOL fIsDfs = FALSE;
  699. PSHARE_INFO_1005 shi1005;
  700. NET_API_STATUS err = CiNetShareGetInfo( pwszServerName,
  701. pwszShareName,
  702. 1005,
  703. (PBYTE *) &shi1005 );
  704. if (err == ERROR_SUCCESS)
  705. {
  706. fIsDfs = ((shi1005->shi1005_flags & SHI1005_FLAGS_DFS) != 0);
  707. //
  708. // Netapi32.dll midl_user_allocate calls LocalAlloc, so use
  709. // LocalFree to free up the stuff the stub allocated.
  710. //
  711. LocalFree( shi1005 );
  712. }
  713. return fIsDfs;
  714. }
  715. void CGenericNotify::LogNotificationsFailed( DWORD dwError ) const
  716. {
  717. Win4Assert( 0 != dwError );
  718. TRY
  719. {
  720. CEventLog eventLog( NULL, wcsCiEventSource );
  721. CEventItem item( EVENTLOG_ERROR_TYPE,
  722. CI_SERVICE_CATEGORY,
  723. MSG_CI_NOTIFICATIONS_TURNED_OFF,
  724. 2 );
  725. item.AddArg( _wcsScope );
  726. //
  727. // When a logon fails, all the other eventlog messages have the
  728. // WIN32 error code in them. Just to keep it consistent, use the
  729. // WIN32 error code here also.
  730. //
  731. if ( STATUS_LOGON_FAILURE == dwError )
  732. dwError = ERROR_LOGON_FAILURE;
  733. item.AddError( dwError );
  734. eventLog.ReportEvent( item );
  735. }
  736. CATCH( CException, e )
  737. {
  738. vqDebugOut(( DEB_ERROR, "Exception 0x%X while writing to event log\n",
  739. e.GetErrorCode() ));
  740. }
  741. END_CATCH
  742. }
  743. void CGenericNotify::LogNoNotifications( DWORD dwError ) const
  744. {
  745. Win4Assert( 0 != dwError );
  746. TRY
  747. {
  748. CEventLog eventLog( NULL, wcsCiEventSource );
  749. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  750. CI_SERVICE_CATEGORY,
  751. MSG_CI_NOTIFICATIONS_NOT_STARTED,
  752. 2 );
  753. item.AddArg( _wcsScope );
  754. //
  755. // When a logon fails, all the other eventlog messages have the
  756. // WIN32 error code in them. Just to keep it consistent, use the
  757. // WIN32 error code here also.
  758. //
  759. if ( STATUS_LOGON_FAILURE == dwError )
  760. dwError = ERROR_LOGON_FAILURE;
  761. item.AddError( dwError );
  762. eventLog.ReportEvent( item );
  763. }
  764. CATCH( CException, e )
  765. {
  766. vqDebugOut(( DEB_ERROR, "Exception 0x%X while writing to event log\n",
  767. e.GetErrorCode() ));
  768. }
  769. END_CATCH
  770. }
  771. //+---------------------------------------------------------------------------
  772. //
  773. // Member: CGenericNotify::LogDfsShare
  774. //
  775. // Synopsis: Logs the the current share is a DFS aware share.
  776. //
  777. // History: 6-27-96 srikants Created
  778. //
  779. //----------------------------------------------------------------------------
  780. void CGenericNotify::LogDfsShare() const
  781. {
  782. TRY
  783. {
  784. CEventLog eventLog( NULL, wcsCiEventSource );
  785. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  786. CI_SERVICE_CATEGORY,
  787. MSG_CI_DFS_SHARE_DETECTED,
  788. 1 );
  789. item.AddArg( _wcsScope );
  790. eventLog.ReportEvent( item );
  791. }
  792. CATCH( CException, e )
  793. {
  794. vqDebugOut(( DEB_ERROR, "Exception 0x%X while writing to event log\n",
  795. e.GetErrorCode() ));
  796. }
  797. END_CATCH
  798. }