11 #include "afsd_init.h"
12 #include "lanahelper.h"
16 #include <WINNT\afsreg.h>
28 //#define REGISTER_POWER_NOTIFICATIONS 1
29 #include "afsd_flushvol.h"
31 extern void afsi_log(char *pattern, ...);
33 static SERVICE_STATUS ServiceStatus;
34 static SERVICE_STATUS_HANDLE StatusHandle;
36 HANDLE hAFSDMainThread = NULL;
38 HANDLE hAFSDWorkerThread[WORKER_THREADS];
41 HANDLE WaitToTerminate;
43 static int GlobalStatus;
46 unsigned int MainThreadId;
50 extern int traceOnPanic;
51 extern HANDLE afsi_file;
53 static int powerEventsRegistered = 0;
54 extern int powerStateSuspended = 0;
57 * Notifier function for use by osi_panic
59 static void afsd_notifier(char *msgp, char *filep, long line)
66 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION,
69 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG, msgp);
73 osi_LogEnable(afsd_logp);
75 afsd_ForceTrace(TRUE);
78 afsi_log("--- begin dump ---");
79 cm_MemDumpDirStats(afsi_file, "a", 0);
80 cm_MemDumpBPlusStats(afsi_file, "a", 0);
81 cm_DumpCells(afsi_file, "a", 0);
82 cm_DumpVolumes(afsi_file, "a", 0);
83 cm_DumpSCache(afsi_file, "a", 0);
85 cm_dnlcDump(afsi_file, "a");
87 cm_DumpBufHashTable(afsi_file, "a", 0);
88 smb_DumpVCP(afsi_file, "a", 0);
89 afsi_log("--- end dump ---");
92 if (IsDebuggerPresent())
96 SetEvent(WaitToTerminate);
98 WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
99 for (i = 0; i < WORKER_THREADS; i++)
100 CloseHandle(hAFSDWorkerThread[i]);
104 if (GetCurrentThreadId() == MainThreadId)
105 longjmp(notifier_jmp, 1);
108 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
109 ServiceStatus.dwWin32ExitCode = NO_ERROR;
110 ServiceStatus.dwCheckPoint = 0;
111 ServiceStatus.dwWaitHint = 0;
112 ServiceStatus.dwControlsAccepted = 0;
113 SetServiceStatus(StatusHandle, &ServiceStatus);
119 * For use miscellaneously in smb.c; need to do better
121 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
127 afsd_ServiceFlushVolume(DWORD dwlpEventData)
129 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
132 ** If UI bit is not set, user interaction is not possible
133 ** BUT, since we are a NON-interactive service, and therefore
134 ** have NO user I/O, it doesn't much matter.
135 ** This benign code left here as example of how to find this out
137 BOOL bUI = (dwlpEventData & 1);
140 if ( PowerNotificationThreadNotify() )
146 /* flush was unsuccessful, or timeout - deny shutdown */
147 dwRet = ERROR_NETWORK_BUSY;
150 /* to deny hibernate, simply return
151 // any value besides NO_ERROR.
153 // dwRet = ERROR_NETWORK_BUSY;
160 /* service control handler used in nt4 only for backward compat. */
162 afsd_ServiceControlHandler(DWORD ctrlCode)
165 DWORD dummyLen, doTrace;
169 case SERVICE_CONTROL_SHUTDOWN:
170 case SERVICE_CONTROL_STOP:
171 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
172 ServiceStatus.dwWin32ExitCode = NO_ERROR;
173 ServiceStatus.dwCheckPoint = 1;
174 ServiceStatus.dwWaitHint = 30000;
175 ServiceStatus.dwControlsAccepted = 0;
176 SetServiceStatus(StatusHandle, &ServiceStatus);
178 if (ctrlCode == SERVICE_CONTROL_STOP)
179 afsi_log("SERVICE_CONTROL_STOP");
181 afsi_log("SERVICE_CONTROL_SHUTDOWN");
183 /* Write all dirty buffers back to server */
184 if ( !lana_OnlyLoopback() )
187 /* Force trace if requested */
188 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
189 AFSREG_CLT_SVC_PARAM_SUBKEY,
190 0, KEY_QUERY_VALUE, &parmKey);
191 if (code != ERROR_SUCCESS)
194 dummyLen = sizeof(doTrace);
195 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
197 (BYTE *) &doTrace, &dummyLen);
198 RegCloseKey (parmKey);
199 if (code != ERROR_SUCCESS)
202 afsd_ForceTrace(FALSE);
203 buf_ForceTrace(FALSE);
207 SetEvent(WaitToTerminate);
210 case SERVICE_CONTROL_INTERROGATE:
211 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
212 ServiceStatus.dwWin32ExitCode = NO_ERROR;
213 ServiceStatus.dwCheckPoint = 0;
214 ServiceStatus.dwWaitHint = 0;
215 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
216 SetServiceStatus(StatusHandle, &ServiceStatus);
218 /* XXX handle system shutdown */
219 /* XXX handle pause & continue */
225 ** Extended ServiceControlHandler that provides Event types
226 ** for monitoring Power events, for example.
229 afsd_ServiceControlHandlerEx(
237 DWORD dummyLen, doTrace;
239 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
240 OSVERSIONINFO osVersion;
242 /* Get the version of Windows */
243 memset(&osVersion, 0x00, sizeof(osVersion));
244 osVersion.dwOSVersionInfoSize = sizeof(osVersion);
245 GetVersionEx(&osVersion);
249 case SERVICE_CONTROL_SHUTDOWN:
250 case SERVICE_CONTROL_STOP:
251 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
252 ServiceStatus.dwWin32ExitCode = NO_ERROR;
253 ServiceStatus.dwCheckPoint = 1;
254 ServiceStatus.dwWaitHint = 30000;
255 ServiceStatus.dwControlsAccepted = 0;
256 SetServiceStatus(StatusHandle, &ServiceStatus);
258 /* Write all dirty buffers back to server */
259 if ( !lana_OnlyLoopback() )
262 /* Force trace if requested */
263 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
264 AFSREG_CLT_SVC_PARAM_SUBKEY,
265 0, KEY_QUERY_VALUE, &parmKey);
266 if (code != ERROR_SUCCESS)
269 dummyLen = sizeof(doTrace);
270 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
272 (BYTE *) &doTrace, &dummyLen);
273 RegCloseKey (parmKey);
274 if (code != ERROR_SUCCESS)
277 afsd_ForceTrace(FALSE);
278 buf_ForceTrace(FALSE);
282 SetEvent(WaitToTerminate);
286 case SERVICE_CONTROL_INTERROGATE:
287 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
288 ServiceStatus.dwWin32ExitCode = NO_ERROR;
289 ServiceStatus.dwCheckPoint = 0;
290 ServiceStatus.dwWaitHint = 0;
291 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
292 SetServiceStatus(StatusHandle, &ServiceStatus);
293 afsi_log("SERVICE_CONTROL_INTERROGATE");
297 /* XXX handle system shutdown */
298 /* XXX handle pause & continue */
299 case SERVICE_CONTROL_POWEREVENT:
302 afsi_log("SERVICE_CONTROL_POWEREVENT");
305 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
306 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
307 ** Return any error code to deny request,
308 ** i.e. as if returning BROADCAST_QUERY_DENY
310 if (powerEventsRegistered) {
311 switch((int) dwEventType)
313 case PBT_APMQUERYSUSPEND:
314 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND");
315 /* Write all dirty buffers back to server */
316 if ( !lana_OnlyLoopback() ) {
320 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete");
323 case PBT_APMQUERYSTANDBY:
324 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY");
325 /* Write all dirty buffers back to server */
326 if ( !lana_OnlyLoopback() ) {
330 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete");
334 /* allow remaining case PBT_WhatEver */
336 afsi_log("SERVICE_CONTROL_APMSUSPEND");
337 powerStateSuspended = 1;
338 if (osVersion.dwMajorVersion >= 6) {
345 afsi_log("SERVICE_CONTROL_APMSTANDBY");
346 powerStateSuspended = 1;
347 if (osVersion.dwMajorVersion >= 6) {
353 case PBT_APMRESUMECRITICAL:
354 afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL");
355 if (osVersion.dwMajorVersion >= 6)
356 smb_RestartListeners();
359 case PBT_APMRESUMESUSPEND:
360 /* User logged in after suspend */
361 afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND");
364 case PBT_APMRESUMESTANDBY:
365 /* User logged in after standby */
366 afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY");
369 case PBT_APMBATTERYLOW:
370 afsi_log("SERVICE_CONTROL_APMBATTERYLOW");
373 case PBT_APMPOWERSTATUSCHANGE:
375 afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
379 case PBT_APMOEMEVENT:
381 afsi_log("SERVICE_CONTROL_APMOEMEVENT");
385 case PBT_APMRESUMEAUTOMATIC:
386 /* This is the message delivered once all devices are up */
387 afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC");
388 powerStateSuspended = 0;
389 if (osVersion.dwMajorVersion >= 6)
390 smb_RestartListeners();
394 afsi_log("SERVICE_CONTROL_unknown");
400 case SERVICE_CONTROL_CUSTOM_DUMP:
402 afsi_log("SERVICE_CONTROL_CUSTOM_DUMP");
403 GenerateMiniDump(NULL);
407 } /* end switch(ctrlCode) */
411 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
413 * Mount a drive into AFS if there global mapping
415 /* DEE Could check first if we are run as SYSTEM */
416 #define MAX_RETRIES 10
417 #define MAX_DRIVES 23
418 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
421 char szAfsPath[_MAX_PATH];
423 char szDriveToMapTo[5];
427 DWORD dwIndex = 0, dwRetry = 0;
429 DWORD dwSubMountSize;
430 char szSubMount[256];
433 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
435 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
436 if (dwResult != ERROR_SUCCESS)
439 while (dwIndex < MAX_DRIVES) {
440 dwDriveSize = sizeof(szDriveToMapTo);
441 dwSubMountSize = sizeof(szSubMount);
442 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
443 if (dwResult != ERROR_MORE_DATA) {
444 if (dwResult != ERROR_SUCCESS) {
445 if (dwResult != ERROR_NO_MORE_ITEMS)
446 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
452 for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
455 memset (&nr, 0x00, sizeof(NETRESOURCE));
457 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
459 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
460 nr.dwType=RESOURCETYPE_DISK;
461 nr.lpLocalName=szDriveToMapTo;
462 nr.lpRemoteName=szAfsPath;
463 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
464 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
466 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
467 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
468 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
469 if (dwResult == NO_ERROR) {
472 /* wait for smb server to come up */
473 Sleep((DWORD)1000 /* miliseconds */);
475 /* Disconnect any previous mappings */
476 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
479 /* FIXFIX: implement */
480 afsi_log("GlobalAutoMap of %s to %s not implemented", szDriveToMapTo, szSubMount);
488 static HANDLE hThreadMountGlobalDrives = NULL;
490 static void MountGlobalDrives()
494 hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
496 if ( hThreadMountGlobalDrives ) {
497 DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
498 if (rc == WAIT_TIMEOUT) {
499 afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
500 } else if (rc == WAIT_OBJECT_0) {
501 afsi_log("GlobalAutoMap thread completed");
502 CloseHandle( hThreadMountGlobalDrives );
503 hThreadMountGlobalDrives = NULL;
508 static void DismountGlobalDrives()
511 char szAfsPath[_MAX_PATH];
512 char szDriveToMapTo[5];
514 DWORD dwSubMountSize;
515 char szSubMount[256];
523 if ( hThreadMountGlobalDrives ) {
524 DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
526 if (rc == WAIT_TIMEOUT) {
527 afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
529 else if (rc == WAIT_OBJECT_0) {
530 afsi_log("GlobalAutoMap thread completed");
531 CloseHandle( hThreadMountGlobalDrives );
532 hThreadMountGlobalDrives = NULL;
536 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
538 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
539 if (dwResult != ERROR_SUCCESS)
543 /* FIXFIX: implement */
545 while (dwIndex < MAX_DRIVES) {
546 dwDriveSize = sizeof(szDriveToMapTo);
547 dwSubMountSize = sizeof(szSubMount);
548 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
549 if (dwResult != ERROR_MORE_DATA) {
550 if (dwResult != ERROR_SUCCESS) {
551 if (dwResult != ERROR_NO_MORE_ITEMS)
552 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
557 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
559 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
560 dwResult = WNetCancelConnection(szAfsPath, TRUE);
562 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
570 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
572 DWORD dwVersionHandle;
573 LPVOID pVersionInfo = 0;
575 LPDWORD pLangInfo = 0;
576 LPTSTR szVersion = 0;
578 TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
579 DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
582 afsi_log("GetFileVersionInfoSize failed");
583 return GetLastError();
586 pVersionInfo = malloc(size);
588 afsi_log("out of memory 1");
589 return ERROR_NOT_ENOUGH_MEMORY;
592 GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
593 if (retval = GetLastError())
595 afsi_log("GetFileVersionInfo failed: %d", retval);
599 VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
600 (LPVOID*)&pLangInfo, &len);
601 if (retval = GetLastError())
603 afsi_log("VerQueryValue 1 failed: %d", retval);
608 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
609 LOWORD(*pLangInfo), HIWORD(*pLangInfo));
611 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
612 if (retval = GetLastError())
614 /* try again with language 409 since the old binaries were tagged wrong */
616 TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
619 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
620 if (retval = GetLastError()) {
621 afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
625 snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
626 szOutput[dwOutput - 1] = 0;
635 static HINSTANCE hCrypt32;
636 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags,
637 void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
638 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
639 DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
640 DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
641 DWORD* pdwFormatType, HCERTSTORE* phCertStore,
642 HCRYPTMSG* phMsg, const void** ppvContext);
643 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
644 void* pvData, DWORD* pcbData);
645 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
646 DWORD dwFindFlags, DWORD dwFindType,
647 const void* pvFindPara,
648 PCCERT_CONTEXT pPrevCertContext);
649 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
650 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
651 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
652 PCERT_INFO pCertId2);
653 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
655 void LoadCrypt32(void)
657 hCrypt32 = LoadLibrary("crypt32");
661 (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
662 (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
663 (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
664 (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
665 (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
666 (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
667 (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
668 (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
670 if ( !pCertGetNameString ||
671 !pCryptQueryObject ||
672 !pCryptMsgGetParam ||
673 !pCertFindCertificateInStore ||
676 !pCertCompareCertificate ||
677 !pCertFreeCertificateContext)
679 FreeLibrary(hCrypt32);
684 void UnloadCrypt32(void)
686 FreeLibrary(hCrypt32);
689 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
691 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
693 wchar_t wfilename[260];
699 HCERTSTORE hStore = NULL;
700 HCRYPTMSG hMsg = NULL;
701 PCMSG_SIGNER_INFO pSignerInfo = NULL;
702 PCCERT_CONTEXT pCertContext = NULL;
705 if ( hCrypt32 == NULL )
708 ZeroMemory(&CertInfo, sizeof(CertInfo));
709 mbstowcs(wfilename, filename, 260);
711 fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
713 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
714 CERT_QUERY_FORMAT_FLAG_BINARY,
724 afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
730 fResult = pCryptMsgGetParam(hMsg,
731 CMSG_SIGNER_INFO_PARAM,
737 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
743 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
745 fResult = pCryptMsgGetParam(hMsg,
746 CMSG_SIGNER_INFO_PARAM,
752 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
758 CertInfo.Issuer = pSignerInfo->Issuer;
759 CertInfo.SerialNumber = pSignerInfo->SerialNumber;
761 pCertContext = pCertFindCertificateInStore(hStore,
764 CERT_FIND_SUBJECT_CERT,
769 afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
777 LocalFree(pSignerInfo);
780 CertFreeCertificateContext(pCertContext);*/
783 pCertCloseStore(hStore,0);
786 pCryptMsgClose(hMsg);
791 BOOL VerifyTrust(CHAR * filename)
793 WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
794 WIN_TRUST_SUBJECT_FILE fSubjectFile;
795 GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
796 GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
797 wchar_t wfilename[260];
799 BOOL success = FALSE;
801 LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
804 if (filename == NULL )
807 hWinTrust = LoadLibrary("wintrust");
811 if (((FARPROC) pWinVerifyTrust =
812 GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
814 FreeLibrary(hWinTrust);
818 mbstowcs(wfilename, filename, 260);
820 fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
822 fSubjectFile.lpPath = wfilename;
823 fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
824 FALSE, GetCurrentProcessId());
825 fContextWSubject.SubjectType = &subject;
826 fContextWSubject.Subject = &fSubjectFile;
828 ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
830 if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
831 CloseHandle( fSubjectFile.hFile );
832 if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
833 CloseHandle( fContextWSubject.hClientToken );
835 if (ret == ERROR_SUCCESS) {
838 DWORD gle = GetLastError();
840 case TRUST_E_PROVIDER_UNKNOWN:
841 afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
843 case TRUST_E_NOSIGNATURE:
844 afsi_log("VerifyTrust failed: Unsigned executable");
846 case TRUST_E_EXPLICIT_DISTRUST:
847 afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
849 case TRUST_E_SUBJECT_NOT_TRUSTED:
850 afsi_log("VerifyTrust failed: File is not trusted");
852 case TRUST_E_BAD_DIGEST:
853 afsi_log("VerifyTrust failed: Executable has been modified");
855 case CRYPT_E_SECURITY_SETTINGS:
856 afsi_log("VerifyTrust failed: local security options prevent verification");
859 afsi_log("VerifyTrust failed: 0x%X", GetLastError());
863 FreeLibrary(hWinTrust);
867 void LogCertCtx(PCCERT_CONTEXT pCtx) {
869 LPTSTR szName = NULL;
871 if ( hCrypt32 == NULL )
874 // Get Issuer name size.
875 if (!(dwData = pCertGetNameString(pCtx,
876 CERT_NAME_SIMPLE_DISPLAY_TYPE,
877 CERT_NAME_ISSUER_FLAG,
881 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
885 // Allocate memory for Issuer name.
886 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
889 if (!(pCertGetNameString(pCtx,
890 CERT_NAME_SIMPLE_DISPLAY_TYPE,
891 CERT_NAME_ISSUER_FLAG,
895 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
899 // print Issuer name.
900 afsi_log("Issuer Name: %s", szName);
904 // Get Subject name size.
905 if (!(dwData = pCertGetNameString(pCtx,
906 CERT_NAME_SIMPLE_DISPLAY_TYPE,
911 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
915 // Allocate memory for subject name.
916 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
919 if (!(pCertGetNameString(pCtx,
920 CERT_NAME_SIMPLE_DISPLAY_TYPE,
925 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
929 // Print Subject Name.
930 afsi_log("Subject Name: %s", szName);
938 BOOL AFSModulesVerify(void)
941 CHAR afsdVersion[128];
942 CHAR modVersion[128];
943 CHAR checkName[1024];
944 BOOL trustVerified = FALSE;
950 PCCERT_CONTEXT pCtxService = NULL;
952 DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
953 BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
954 DWORD dummyLen, code;
955 DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
956 DWORD verifyServiceSig = TRUE;
959 hPSAPI = LoadLibrary("psapi");
961 if ( hPSAPI == NULL )
964 if (!GetModuleFileName(NULL, filename, sizeof(filename)))
967 if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
970 afsi_log("%s version %s", filename, afsdVersion);
972 if (((FARPROC) pGetModuleFileNameExA =
973 GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
974 ((FARPROC) pEnumProcessModules =
975 GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
982 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
983 AFSREG_CLT_SVC_PARAM_SUBKEY,
984 0, KEY_QUERY_VALUE, &parmKey);
985 if (code == ERROR_SUCCESS) {
986 dummyLen = sizeof(cacheSize);
987 code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
988 (BYTE *) &cacheSize, &dummyLen);
989 RegCloseKey (parmKey);
992 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
993 0, KEY_QUERY_VALUE, &parmKey);
994 if (code == ERROR_SUCCESS) {
995 dummyLen = sizeof(verifyServiceSig);
996 code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
997 (BYTE *) &verifyServiceSig, &dummyLen);
998 RegCloseKey (parmKey);
1001 if (verifyServiceSig && cacheSize < 716800) {
1002 trustVerified = VerifyTrust(filename);
1004 afsi_log("Signature Verification disabled");
1007 if (trustVerified) {
1010 // get a certificate context for the signer of afsd_service.
1011 pCtxService = GetCertCtx(filename);
1013 LogCertCtx(pCtxService);
1016 // Get a list of all the modules in this process.
1017 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1018 FALSE, GetCurrentProcessId());
1020 if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1022 afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1024 for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1026 char szModName[2048];
1028 // Get the full path to the module's file.
1029 if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1031 lstrcpy(checkName, szModName);
1034 if ( strstr(checkName, "afspthread.dll") ||
1035 strstr(checkName, "afsauthent.dll") ||
1036 strstr(checkName, "afsrpc.dll") ||
1037 strstr(checkName, "libafsconf.dll") ||
1038 strstr(checkName, "libosi.dll") )
1040 if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1045 afsi_log("%s version %s", szModName, modVersion);
1046 if (strcmp(afsdVersion,modVersion)) {
1047 afsi_log("Version mismatch: %s", szModName);
1050 if ( trustVerified ) {
1051 if ( !VerifyTrust(szModName) ) {
1052 afsi_log("Signature Verification failed: %s", szModName);
1055 else if (pCtxService) {
1056 PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1058 if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1059 pCtxService->pCertInfo,
1061 afsi_log("Certificate mismatch: %s", szModName);
1069 pCertFreeCertificateContext(pCtx);
1078 pCertFreeCertificateContext(pCtxService);
1082 FreeLibrary(hPSAPI);
1084 CloseHandle(hProcess);
1089 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1092 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1093 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
1095 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1096 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
1099 afsd_Main(DWORD argc, LPTSTR *argv)
1113 afsd_DbgBreakAllocInit();
1114 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
1115 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1118 afsd_SetUnhandledExceptionFilter();
1120 osi_InitPanic(afsd_notifier);
1121 osi_InitTraceOption();
1127 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1128 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1129 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1132 hAdvApi32 = LoadLibrary("advapi32.dll");
1133 if (hAdvApi32 == NULL)
1135 afsi_log("Fatal: cannot load advapi32.dll");
1139 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
1140 if (pRegisterServiceCtrlHandlerEx)
1142 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
1143 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
1147 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
1150 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1151 ServiceStatus.dwServiceSpecificExitCode = 0;
1152 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1153 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1154 ServiceStatus.dwCheckPoint = 1;
1155 ServiceStatus.dwWaitHint = 120000;
1156 /* accept Power Events */
1157 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1158 SetServiceStatus(StatusHandle, &ServiceStatus);
1161 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
1163 #ifdef REGISTER_POWER_NOTIFICATIONS
1170 /* see if we should handle power notifications */
1171 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1172 0, KEY_QUERY_VALUE, &hkParm);
1173 if (code == ERROR_SUCCESS) {
1174 dummyLen = sizeof(bpower);
1175 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
1176 (BYTE *) &bpower, &dummyLen);
1178 if(code != ERROR_SUCCESS)
1181 RegCloseKey(hkParm);
1183 /* create thread used to flush cache */
1185 PowerNotificationThreadCreate();
1186 powerEventsRegistered = 1;
1191 /* Verify the versions of the DLLs which were loaded */
1192 if (!AFSModulesVerify()) {
1193 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1194 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1195 ServiceStatus.dwCheckPoint = 0;
1196 ServiceStatus.dwWaitHint = 0;
1197 ServiceStatus.dwControlsAccepted = 0;
1198 SetServiceStatus(StatusHandle, &ServiceStatus);
1200 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1202 /* exit if initialization failed */
1206 /* allow an exit to be called prior to any initialization */
1207 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1211 AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1214 hookRc = initHook();
1216 FreeLibrary(hHookDll);
1219 if (hookRc == FALSE)
1221 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1222 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1223 ServiceStatus.dwCheckPoint = 0;
1224 ServiceStatus.dwWaitHint = 0;
1225 ServiceStatus.dwControlsAccepted = 0;
1226 SetServiceStatus(StatusHandle, &ServiceStatus);
1228 /* exit if initialization failed */
1233 /* allow another 120 seconds to start */
1234 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1235 ServiceStatus.dwServiceSpecificExitCode = 0;
1236 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1237 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1238 ServiceStatus.dwCheckPoint = 2;
1239 ServiceStatus.dwWaitHint = 120000;
1240 /* accept Power Events */
1241 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1242 SetServiceStatus(StatusHandle, &ServiceStatus);
1246 /* Perform Volume Status Notification Initialization */
1247 cm_VolStatus_Initialization();
1250 MainThreadId = GetCurrentThreadId();
1251 jmpret = setjmp(notifier_jmp);
1256 code = afsd_InitCM(&reason);
1258 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1259 osi_panic(reason, __FILE__, __LINE__);
1263 ServiceStatus.dwCheckPoint = 3;
1264 ServiceStatus.dwWaitHint = 30000;
1265 SetServiceStatus(StatusHandle, &ServiceStatus);
1267 code = afsd_InitDaemons(&reason);
1269 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1270 osi_panic(reason, __FILE__, __LINE__);
1273 /* allow an exit to be called post rx initialization */
1274 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1278 AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1281 hookRc = rxStartedHook();
1283 FreeLibrary(hHookDll);
1286 if (hookRc == FALSE)
1288 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1289 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1290 ServiceStatus.dwCheckPoint = 0;
1291 ServiceStatus.dwWaitHint = 0;
1292 ServiceStatus.dwControlsAccepted = 0;
1293 SetServiceStatus(StatusHandle, &ServiceStatus);
1295 /* exit if initialization failed */
1301 ServiceStatus.dwCheckPoint = 4;
1302 ServiceStatus.dwWaitHint = 15000;
1303 SetServiceStatus(StatusHandle, &ServiceStatus);
1306 /* the following ifdef chooses the mode of operation for the service. to enable
1307 * a runtime flag (instead of compile-time), pioctl() would need to dynamically
1308 * determine the mode, in order to use the correct ioctl special-file path. */
1310 code = afsd_InitSMB(&reason, MessageBox);
1312 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1313 osi_panic(reason, __FILE__, __LINE__);
1316 code = ifs_Init(&reason);
1318 afsi_log("ifs_Init failed: %s (code = %d)", reason, code);
1319 osi_panic(reason, __FILE__, __LINE__);
1321 for (cnt = 0; cnt < WORKER_THREADS; cnt++)
1322 hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL);
1325 /* allow an exit to be called post smb initialization */
1326 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1330 AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1333 hookRc = smbStartedHook();
1335 FreeLibrary(hHookDll);
1338 if (hookRc == FALSE)
1340 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1341 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1342 ServiceStatus.dwCheckPoint = 0;
1343 ServiceStatus.dwWaitHint = 0;
1344 ServiceStatus.dwControlsAccepted = 0;
1345 SetServiceStatus(StatusHandle, &ServiceStatus);
1347 /* exit if initialization failed */
1352 MountGlobalDrives();
1355 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1356 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1357 ServiceStatus.dwCheckPoint = 5;
1358 ServiceStatus.dwWaitHint = 0;
1360 /* accept Power events */
1361 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1362 SetServiceStatus(StatusHandle, &ServiceStatus);
1365 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1368 /* Notify any volume status handlers that we have started */
1369 cm_VolStatus_Service_Started();
1371 /* allow an exit to be called when started */
1372 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1376 AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1379 hookRc = startedHook();
1381 FreeLibrary(hHookDll);
1384 if (hookRc == FALSE)
1386 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1387 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1388 ServiceStatus.dwCheckPoint = 0;
1389 ServiceStatus.dwWaitHint = 0;
1390 ServiceStatus.dwControlsAccepted = 0;
1391 SetServiceStatus(StatusHandle, &ServiceStatus);
1393 /* exit if initialization failed */
1399 WaitForSingleObject(WaitToTerminate, INFINITE);
1401 WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
1402 for (cnt = 0; cnt < WORKER_THREADS; cnt++)
1403 CloseHandle(hAFSDWorkerThread[cnt]);
1406 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1407 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1408 ServiceStatus.dwCheckPoint = 6;
1409 ServiceStatus.dwWaitHint = 120000;
1410 ServiceStatus.dwControlsAccepted = 0;
1411 SetServiceStatus(StatusHandle, &ServiceStatus);
1413 afsi_log("Received Termination Signal, Stopping Service");
1416 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP);
1418 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
1420 /* allow an exit to be called prior to stopping the service */
1421 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1425 AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
1428 hookRc = stoppingHook();
1430 FreeLibrary(hHookDll);
1435 #ifdef AFS_FREELANCE_CLIENT
1436 cm_FreelanceShutdown();
1437 afsi_log("Freelance Shutdown complete");
1440 DismountGlobalDrives();
1441 afsi_log("Global Drives dismounted");
1443 cm_DaemonShutdown();
1444 afsi_log("Daemon shutdown complete");
1449 afsi_log("Buffer shutdown complete");
1452 afsi_log("rx finalization complete");
1456 afsi_log("smb shutdown complete");
1461 cm_ReleaseAllLocks();
1464 afsi_log("rx finalization complete");
1466 cm_ShutdownMappedMemory();
1468 #ifdef REGISTER_POWER_NOTIFICATIONS
1469 /* terminate thread used to flush cache */
1470 if (powerEventsRegistered)
1471 PowerNotificationThreadExit();
1476 cm_BPlusDumpStats();
1479 /* Notify any Volume Status Handlers that we are stopped */
1480 cm_VolStatus_Service_Stopped();
1482 /* Cleanup any Volume Status Notification Handler */
1483 cm_VolStatus_Finalize();
1485 /* allow an exit to be called after stopping the service */
1486 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1490 AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1493 hookRc = stoppedHook();
1495 FreeLibrary(hHookDll);
1499 /* Remove the ExceptionFilter */
1500 SetUnhandledExceptionFilter(NULL);
1502 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1503 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1504 ServiceStatus.dwCheckPoint = 7;
1505 ServiceStatus.dwWaitHint = 0;
1506 ServiceStatus.dwControlsAccepted = 0;
1507 SetServiceStatus(StatusHandle, &ServiceStatus);
1510 DWORD __stdcall afsdMain_thread(void* notUsed)
1512 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1513 afsd_Main(1, (LPTSTR*)argv);
1519 fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1523 main(int argc, char * argv[])
1525 static SERVICE_TABLE_ENTRY dispatchTable[] = {
1526 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1531 for (i = 1; i < argc; i++) {
1532 if (!stricmp(argv[i],"--validate-cache")) {
1533 if (++i != argc - 1) {
1538 return cm_ValidateMappedMemory(argv[i]);
1545 if (!StartServiceCtrlDispatcher(dispatchTable))
1547 LONG status = GetLastError();
1548 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1551 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1553 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1555 SetEvent(WaitToTerminate);
1562 if ( hAFSDMainThread ) {
1563 WaitForSingleObject( hAFSDMainThread, INFINITE );
1564 CloseHandle( hAFSDMainThread );