11 #include "afsd_init.h"
12 #include "lanahelper.h"
16 #include <WINNT\afsreg.h>
30 //#define REGISTER_POWER_NOTIFICATIONS 1
31 #include "afsd_flushvol.h"
33 extern void afsi_log(char *pattern, ...);
35 static SERVICE_STATUS ServiceStatus;
36 static SERVICE_STATUS_HANDLE StatusHandle;
37 static BOOL bRunningAsService = TRUE;
39 HANDLE hAFSDMainThread = NULL;
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;
56 static VOID (WINAPI* pRtlCaptureContext)(PCONTEXT ContextRecord) = NULL;
59 * Notifier function for use by osi_panic
61 static void afsd_notifier(char *msgp, char *filep, long line)
66 msgp = "unspecified assert";
69 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION,
72 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG, msgp);
76 osi_LogEnable(afsd_logp);
78 afsd_ForceTrace(TRUE);
81 if (pRtlCaptureContext) {
82 pRtlCaptureContext(&context);
83 afsd_printStack(GetCurrentThread(), &context);
86 afsi_log("--- begin dump ---");
87 cm_MemDumpDirStats(afsi_file, "a", 0);
88 cm_MemDumpBPlusStats(afsi_file, "a", 0);
89 cm_DumpCells(afsi_file, "a", 0);
90 cm_DumpVolumes(afsi_file, "a", 0);
91 cm_DumpSCache(afsi_file, "a", 0);
92 cm_DumpBufHashTable(afsi_file, "a", 0);
93 smb_DumpVCP(afsi_file, "a", 0);
94 rx_DumpPackets(afsi_file, "a");
95 rx_DumpCalls(afsi_file, "a");
96 afsi_log("--- end dump ---");
99 if (IsDebuggerPresent())
103 GenerateMiniDump(NULL);
105 SetEvent(WaitToTerminate);
108 if (GetCurrentThreadId() == MainThreadId)
109 longjmp(notifier_jmp, 1);
112 if (bRunningAsService) {
113 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
114 ServiceStatus.dwWin32ExitCode = NO_ERROR;
115 ServiceStatus.dwCheckPoint = 0;
116 ServiceStatus.dwWaitHint = 0;
117 ServiceStatus.dwControlsAccepted = 0;
118 SetServiceStatus(StatusHandle, &ServiceStatus);
124 * For use miscellaneously in smb.c; need to do better
126 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
132 afsd_ServiceFlushVolume(DWORD dwlpEventData)
134 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
137 ** If UI bit is not set, user interaction is not possible
138 ** BUT, since we are a NON-interactive service, and therefore
139 ** have NO user I/O, it doesn't much matter.
140 ** This benign code left here as example of how to find this out
142 BOOL bUI = (dwlpEventData & 1);
145 if ( PowerNotificationThreadNotify() )
151 /* flush was unsuccessful, or timeout - deny shutdown */
152 dwRet = ERROR_NETWORK_BUSY;
155 /* to deny hibernate, simply return
156 // any value besides NO_ERROR.
158 // dwRet = ERROR_NETWORK_BUSY;
165 /* service control handler used in nt4 only for backward compat. */
167 afsd_ServiceControlHandler(DWORD ctrlCode)
170 DWORD dummyLen, doTrace;
174 case SERVICE_CONTROL_SHUTDOWN:
175 case SERVICE_CONTROL_STOP:
176 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
177 ServiceStatus.dwWin32ExitCode = NO_ERROR;
178 ServiceStatus.dwCheckPoint = 1;
179 ServiceStatus.dwWaitHint = 30000;
180 ServiceStatus.dwControlsAccepted = 0;
181 SetServiceStatus(StatusHandle, &ServiceStatus);
183 if (ctrlCode == SERVICE_CONTROL_STOP)
184 afsi_log("SERVICE_CONTROL_STOP");
186 afsi_log("SERVICE_CONTROL_SHUTDOWN");
188 /* Write all dirty buffers back to server */
189 if ( !lana_OnlyLoopback() )
192 /* Force trace if requested */
193 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
194 AFSREG_CLT_SVC_PARAM_SUBKEY,
195 0, KEY_QUERY_VALUE, &parmKey);
196 if (code != ERROR_SUCCESS)
199 dummyLen = sizeof(doTrace);
200 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
202 (BYTE *) &doTrace, &dummyLen);
203 RegCloseKey (parmKey);
204 if (code != ERROR_SUCCESS)
207 afsd_ForceTrace(FALSE);
208 buf_ForceTrace(FALSE);
212 SetEvent(WaitToTerminate);
215 case SERVICE_CONTROL_INTERROGATE:
216 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
217 ServiceStatus.dwWin32ExitCode = NO_ERROR;
218 ServiceStatus.dwCheckPoint = 0;
219 ServiceStatus.dwWaitHint = 0;
220 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
221 SetServiceStatus(StatusHandle, &ServiceStatus);
223 /* XXX handle system shutdown */
224 /* XXX handle pause & continue */
230 ** Extended ServiceControlHandler that provides Event types
231 ** for monitoring Power events, for example.
234 afsd_ServiceControlHandlerEx(
242 DWORD dummyLen, doTrace;
244 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
245 OSVERSIONINFO osVersion;
247 /* Get the version of Windows */
248 memset(&osVersion, 0x00, sizeof(osVersion));
249 osVersion.dwOSVersionInfoSize = sizeof(osVersion);
250 GetVersionEx(&osVersion);
254 case SERVICE_CONTROL_SHUTDOWN:
255 case SERVICE_CONTROL_STOP:
256 if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
257 afsi_log("SERVICE_CONTROL_SHUTDOWN");
259 afsi_log("SERVICE_CONTROL_STOP");
261 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
262 ServiceStatus.dwWin32ExitCode = NO_ERROR;
263 ServiceStatus.dwCheckPoint = 1;
264 ServiceStatus.dwWaitHint = 30000;
265 ServiceStatus.dwControlsAccepted = 0;
266 SetServiceStatus(StatusHandle, &ServiceStatus);
268 /* Write all dirty buffers back to server */
269 if ( !lana_OnlyLoopback() )
272 /* Force trace if requested */
273 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
274 AFSREG_CLT_SVC_PARAM_SUBKEY,
275 0, KEY_QUERY_VALUE, &parmKey);
276 if (code != ERROR_SUCCESS)
279 dummyLen = sizeof(doTrace);
280 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
282 (BYTE *) &doTrace, &dummyLen);
283 RegCloseKey (parmKey);
284 if (code != ERROR_SUCCESS)
287 afsd_ForceTrace(FALSE);
288 buf_ForceTrace(FALSE);
292 SetEvent(WaitToTerminate);
296 case SERVICE_CONTROL_INTERROGATE:
297 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
298 ServiceStatus.dwWin32ExitCode = NO_ERROR;
299 ServiceStatus.dwCheckPoint = 0;
300 ServiceStatus.dwWaitHint = 0;
301 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
302 SetServiceStatus(StatusHandle, &ServiceStatus);
303 afsi_log("SERVICE_CONTROL_INTERROGATE");
307 /* XXX handle system shutdown */
308 /* XXX handle pause & continue */
309 case SERVICE_CONTROL_POWEREVENT:
312 afsi_log("SERVICE_CONTROL_POWEREVENT");
315 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
316 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
317 ** Return any error code to deny request,
318 ** i.e. as if returning BROADCAST_QUERY_DENY
320 if (powerEventsRegistered) {
321 switch((int) dwEventType)
323 case PBT_APMQUERYSUSPEND:
324 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND");
325 /* Write all dirty buffers back to server */
326 if ( !lana_OnlyLoopback() ) {
330 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete");
333 case PBT_APMQUERYSTANDBY:
334 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY");
335 /* Write all dirty buffers back to server */
336 if ( !lana_OnlyLoopback() ) {
340 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete");
344 /* allow remaining case PBT_WhatEver */
346 afsi_log("SERVICE_CONTROL_APMSUSPEND");
347 powerStateSuspended = 1;
348 if (osVersion.dwMajorVersion >= 6) {
350 smb_StopListeners(0);
355 afsi_log("SERVICE_CONTROL_APMSTANDBY");
356 powerStateSuspended = 1;
357 if (osVersion.dwMajorVersion >= 6) {
359 smb_StopListeners(0);
363 case PBT_APMRESUMECRITICAL:
364 afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL");
365 if (osVersion.dwMajorVersion >= 6)
366 smb_RestartListeners(0);
369 case PBT_APMRESUMESUSPEND:
370 /* User logged in after suspend */
371 afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND");
374 case PBT_APMRESUMESTANDBY:
375 /* User logged in after standby */
376 afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY");
379 case PBT_APMBATTERYLOW:
380 afsi_log("SERVICE_CONTROL_APMBATTERYLOW");
383 case PBT_APMPOWERSTATUSCHANGE:
385 afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
389 case PBT_APMOEMEVENT:
391 afsi_log("SERVICE_CONTROL_APMOEMEVENT");
395 case PBT_APMRESUMEAUTOMATIC:
396 /* This is the message delivered once all devices are up */
397 afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC");
398 powerStateSuspended = 0;
399 if (osVersion.dwMajorVersion >= 6) {
400 smb_SetLanAdapterChangeDetected();
405 afsi_log("SERVICE_CONTROL_unknown");
411 case SERVICE_CONTROL_CUSTOM_DUMP:
413 afsi_log("SERVICE_CONTROL_CUSTOM_DUMP");
414 GenerateMiniDump(NULL);
418 } /* end switch(ctrlCode) */
422 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
424 * Mount a drive into AFS if there global mapping
426 /* DEE Could check first if we are run as SYSTEM */
427 #define MAX_RETRIES 10
428 #define MAX_DRIVES 23
429 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
431 char szAfsPath[_MAX_PATH];
432 char szDriveToMapTo[5];
436 DWORD dwIndex = 0, dwRetry = 0;
438 DWORD dwSubMountSize;
439 char szSubMount[256];
442 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
444 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
445 if (dwResult != ERROR_SUCCESS)
448 while (dwIndex < MAX_DRIVES) {
449 dwDriveSize = sizeof(szDriveToMapTo);
450 dwSubMountSize = sizeof(szSubMount);
451 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
452 if (dwResult != ERROR_MORE_DATA) {
453 if (dwResult != ERROR_SUCCESS) {
454 if (dwResult != ERROR_NO_MORE_ITEMS)
455 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
460 for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
463 memset (&nr, 0x00, sizeof(NETRESOURCE));
465 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
467 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
468 nr.dwType=RESOURCETYPE_DISK;
469 nr.lpLocalName=szDriveToMapTo;
470 nr.lpRemoteName=szAfsPath;
471 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
472 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
474 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
475 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
476 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
477 if (dwResult == NO_ERROR) {
480 /* wait for smb server to come up */
481 Sleep((DWORD)1000 /* miliseconds */);
483 /* Disconnect any previous mappings */
484 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
492 static HANDLE hThreadMountGlobalDrives = NULL;
494 static void MountGlobalDrives()
498 hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
500 if ( hThreadMountGlobalDrives ) {
501 DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
502 if (rc == WAIT_TIMEOUT) {
503 afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
504 } else if (rc == WAIT_OBJECT_0) {
505 afsi_log("GlobalAutoMap thread completed");
506 CloseHandle( hThreadMountGlobalDrives );
507 hThreadMountGlobalDrives = NULL;
512 static void DismountGlobalDrives()
514 char szAfsPath[_MAX_PATH];
515 char szDriveToMapTo[5];
517 DWORD dwSubMountSize;
518 char szSubMount[256];
525 if ( hThreadMountGlobalDrives ) {
526 DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
528 if (rc == WAIT_TIMEOUT) {
529 afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
531 else if (rc == WAIT_OBJECT_0) {
532 afsi_log("GlobalAutoMap thread completed");
533 CloseHandle( hThreadMountGlobalDrives );
534 hThreadMountGlobalDrives = NULL;
538 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
540 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
541 if (dwResult != ERROR_SUCCESS)
544 while (dwIndex < MAX_DRIVES) {
545 dwDriveSize = sizeof(szDriveToMapTo);
546 dwSubMountSize = sizeof(szSubMount);
547 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
548 if (dwResult != ERROR_MORE_DATA) {
549 if (dwResult != ERROR_SUCCESS) {
550 if (dwResult != ERROR_NO_MORE_ITEMS)
551 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
556 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
558 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
559 dwResult = WNetCancelConnection(szAfsPath, TRUE);
561 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
568 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
570 DWORD dwVersionHandle;
571 LPVOID pVersionInfo = 0;
573 LPDWORD pLangInfo = 0;
574 LPTSTR szVersion = 0;
576 TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
577 DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
580 afsi_log("GetFileVersionInfoSize failed");
581 return GetLastError();
584 pVersionInfo = malloc(size);
586 afsi_log("out of memory 1");
587 return ERROR_NOT_ENOUGH_MEMORY;
590 GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
591 if (retval = GetLastError())
593 afsi_log("GetFileVersionInfo failed: %d", retval);
597 VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
598 (LPVOID*)&pLangInfo, &len);
599 if (retval = GetLastError())
601 afsi_log("VerQueryValue 1 failed: %d", retval);
606 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
607 LOWORD(*pLangInfo), HIWORD(*pLangInfo));
609 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
610 if (retval = GetLastError())
612 /* try again with language 409 since the old binaries were tagged wrong */
614 TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
617 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
618 if (retval = GetLastError()) {
619 afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
623 snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
624 szOutput[dwOutput - 1] = 0;
633 static HINSTANCE hCrypt32;
634 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags,
635 void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
636 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
637 DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
638 DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
639 DWORD* pdwFormatType, HCERTSTORE* phCertStore,
640 HCRYPTMSG* phMsg, const void** ppvContext);
641 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
642 void* pvData, DWORD* pcbData);
643 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
644 DWORD dwFindFlags, DWORD dwFindType,
645 const void* pvFindPara,
646 PCCERT_CONTEXT pPrevCertContext);
647 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
648 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
649 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
650 PCERT_INFO pCertId2);
651 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
653 void LoadCrypt32(void)
655 hCrypt32 = LoadLibrary("crypt32");
659 (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
660 (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
661 (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
662 (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
663 (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
664 (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
665 (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
666 (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
668 if ( !pCertGetNameString ||
669 !pCryptQueryObject ||
670 !pCryptMsgGetParam ||
671 !pCertFindCertificateInStore ||
674 !pCertCompareCertificate ||
675 !pCertFreeCertificateContext)
677 FreeLibrary(hCrypt32);
682 void UnloadCrypt32(void)
684 FreeLibrary(hCrypt32);
687 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
689 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
691 wchar_t wfilename[260];
697 HCERTSTORE hStore = NULL;
698 HCRYPTMSG hMsg = NULL;
699 PCMSG_SIGNER_INFO pSignerInfo = NULL;
700 PCCERT_CONTEXT pCertContext = NULL;
703 if ( hCrypt32 == NULL )
706 ZeroMemory(&CertInfo, sizeof(CertInfo));
707 mbstowcs(wfilename, filename, 260);
709 fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
711 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
712 CERT_QUERY_FORMAT_FLAG_BINARY,
722 afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
728 fResult = pCryptMsgGetParam(hMsg,
729 CMSG_SIGNER_INFO_PARAM,
735 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
741 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
743 fResult = pCryptMsgGetParam(hMsg,
744 CMSG_SIGNER_INFO_PARAM,
750 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
756 CertInfo.Issuer = pSignerInfo->Issuer;
757 CertInfo.SerialNumber = pSignerInfo->SerialNumber;
759 pCertContext = pCertFindCertificateInStore(hStore,
762 CERT_FIND_SUBJECT_CERT,
767 afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
775 LocalFree(pSignerInfo);
778 CertFreeCertificateContext(pCertContext);*/
781 pCertCloseStore(hStore,0);
784 pCryptMsgClose(hMsg);
789 BOOL VerifyTrust(CHAR * filename)
791 WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
792 WIN_TRUST_SUBJECT_FILE fSubjectFile;
793 GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
794 GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
795 wchar_t wfilename[260];
797 BOOL success = FALSE;
799 LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
802 if (filename == NULL )
805 hWinTrust = LoadLibrary("wintrust");
809 if (((FARPROC) pWinVerifyTrust =
810 GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
812 FreeLibrary(hWinTrust);
816 mbstowcs(wfilename, filename, 260);
818 fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
820 fSubjectFile.lpPath = wfilename;
821 fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
822 FALSE, GetCurrentProcessId());
823 fContextWSubject.SubjectType = &subject;
824 fContextWSubject.Subject = &fSubjectFile;
826 ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
828 if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
829 CloseHandle( fSubjectFile.hFile );
830 if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
831 CloseHandle( fContextWSubject.hClientToken );
833 if (ret == ERROR_SUCCESS) {
836 DWORD gle = GetLastError();
838 case TRUST_E_PROVIDER_UNKNOWN:
839 afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
841 case TRUST_E_NOSIGNATURE:
842 afsi_log("VerifyTrust failed: Unsigned executable");
844 case TRUST_E_EXPLICIT_DISTRUST:
845 afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
847 case TRUST_E_SUBJECT_NOT_TRUSTED:
848 afsi_log("VerifyTrust failed: File is not trusted");
850 case TRUST_E_BAD_DIGEST:
851 afsi_log("VerifyTrust failed: Executable has been modified");
853 case CRYPT_E_SECURITY_SETTINGS:
854 afsi_log("VerifyTrust failed: local security options prevent verification");
857 afsi_log("VerifyTrust failed: 0x%X", GetLastError());
861 FreeLibrary(hWinTrust);
865 void LogCertCtx(PCCERT_CONTEXT pCtx) {
867 LPTSTR szName = NULL;
869 if ( hCrypt32 == NULL )
872 // Get Issuer name size.
873 if (!(dwData = pCertGetNameString(pCtx,
874 CERT_NAME_SIMPLE_DISPLAY_TYPE,
875 CERT_NAME_ISSUER_FLAG,
879 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
883 // Allocate memory for Issuer name.
884 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
887 if (!(pCertGetNameString(pCtx,
888 CERT_NAME_SIMPLE_DISPLAY_TYPE,
889 CERT_NAME_ISSUER_FLAG,
893 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
897 // print Issuer name.
898 afsi_log("Issuer Name: %s", szName);
902 // Get Subject name size.
903 if (!(dwData = pCertGetNameString(pCtx,
904 CERT_NAME_SIMPLE_DISPLAY_TYPE,
909 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
913 // Allocate memory for subject name.
914 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
917 if (!(pCertGetNameString(pCtx,
918 CERT_NAME_SIMPLE_DISPLAY_TYPE,
923 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
927 // Print Subject Name.
928 afsi_log("Subject Name: %s", szName);
936 BOOL AFSModulesVerify(void)
939 CHAR afsdVersion[128];
940 CHAR modVersion[128];
941 CHAR checkName[1024];
942 BOOL trustVerified = FALSE;
948 PCCERT_CONTEXT pCtxService = NULL;
950 DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
951 BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
952 DWORD dummyLen, code;
953 DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
954 DWORD verifyServiceSig = TRUE;
957 hPSAPI = LoadLibrary("psapi");
959 if ( hPSAPI == NULL )
962 if (!GetModuleFileName(NULL, filename, sizeof(filename)))
965 if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
968 afsi_log("%s version %s", filename, afsdVersion);
970 if (((FARPROC) pGetModuleFileNameExA =
971 GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
972 ((FARPROC) pEnumProcessModules =
973 GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
980 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
981 AFSREG_CLT_SVC_PARAM_SUBKEY,
982 0, KEY_QUERY_VALUE, &parmKey);
983 if (code == ERROR_SUCCESS) {
984 dummyLen = sizeof(cacheSize);
985 code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
986 (BYTE *) &cacheSize, &dummyLen);
987 RegCloseKey (parmKey);
990 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
991 0, KEY_QUERY_VALUE, &parmKey);
992 if (code == ERROR_SUCCESS) {
993 dummyLen = sizeof(verifyServiceSig);
994 code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
995 (BYTE *) &verifyServiceSig, &dummyLen);
996 RegCloseKey (parmKey);
1001 && cacheSize < 716800
1004 trustVerified = VerifyTrust(filename);
1006 afsi_log("Signature Verification disabled");
1009 if (trustVerified) {
1012 // get a certificate context for the signer of afsd_service.
1013 pCtxService = GetCertCtx(filename);
1015 LogCertCtx(pCtxService);
1018 // Get a list of all the modules in this process.
1019 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1020 FALSE, GetCurrentProcessId());
1022 if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1024 afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1026 for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1028 char szModName[2048];
1030 // Get the full path to the module's file.
1031 if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1033 lstrcpy(checkName, szModName);
1036 if ( strstr(checkName, "afspthread.dll") ||
1037 strstr(checkName, "afsauthent.dll") ||
1038 strstr(checkName, "afsrpc.dll") ||
1039 strstr(checkName, "libafsconf.dll") ||
1040 strstr(checkName, "libosi.dll") )
1042 if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1047 afsi_log("%s version %s", szModName, modVersion);
1048 if (strcmp(afsdVersion,modVersion)) {
1049 afsi_log("Version mismatch: %s", szModName);
1052 if ( trustVerified ) {
1053 if ( !VerifyTrust(szModName) ) {
1054 afsi_log("Signature Verification failed: %s", szModName);
1057 else if (pCtxService) {
1058 PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1060 if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1061 pCtxService->pCertInfo,
1063 afsi_log("Certificate mismatch: %s", szModName);
1071 pCertFreeCertificateContext(pCtx);
1080 pCertFreeCertificateContext(pCtxService);
1084 FreeLibrary(hPSAPI);
1086 CloseHandle(hProcess);
1091 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1094 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1095 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
1097 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1098 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
1101 afsd_Main(DWORD argc, LPTSTR *argv)
1113 void afsd_DbgBreakAllocInit();
1115 afsd_DbgBreakAllocInit();
1116 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
1117 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1120 afsd_SetUnhandledExceptionFilter();
1122 osi_InitPanic(afsd_notifier);
1123 osi_InitTraceOption();
1125 hKernel32 = LoadLibrary("kernel32.dll");
1126 if (hKernel32 == NULL)
1128 afsi_log("Fatal: cannot load kernel32.dll");
1131 pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
1137 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1138 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1139 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1142 hAdvApi32 = LoadLibrary("advapi32.dll");
1143 if (hAdvApi32 == NULL)
1145 afsi_log("Fatal: cannot load advapi32.dll");
1149 if (bRunningAsService) {
1150 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
1151 if (pRegisterServiceCtrlHandlerEx)
1153 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
1154 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
1158 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
1161 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1162 ServiceStatus.dwServiceSpecificExitCode = 0;
1163 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1164 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1165 ServiceStatus.dwCheckPoint = 1;
1166 ServiceStatus.dwWaitHint = 120000;
1167 /* accept Power Events */
1168 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1169 SetServiceStatus(StatusHandle, &ServiceStatus);
1173 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
1175 #ifdef REGISTER_POWER_NOTIFICATIONS
1182 /* see if we should handle power notifications */
1183 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1184 0, KEY_QUERY_VALUE, &hkParm);
1185 if (code == ERROR_SUCCESS) {
1186 dummyLen = sizeof(bpower);
1187 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
1188 (BYTE *) &bpower, &dummyLen);
1190 if(code != ERROR_SUCCESS)
1193 RegCloseKey(hkParm);
1195 /* create thread used to flush cache */
1197 PowerNotificationThreadCreate();
1198 powerEventsRegistered = 1;
1203 /* Verify the versions of the DLLs which were loaded */
1204 if (!AFSModulesVerify()) {
1205 if (bRunningAsService) {
1206 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1207 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1208 ServiceStatus.dwCheckPoint = 0;
1209 ServiceStatus.dwWaitHint = 0;
1210 ServiceStatus.dwControlsAccepted = 0;
1211 SetServiceStatus(StatusHandle, &ServiceStatus);
1213 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1215 /* exit if initialization failed */
1219 /* allow an exit to be called prior to any initialization */
1220 hHookDll = cm_LoadAfsdHookLib();
1224 AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1227 hookRc = initHook();
1229 FreeLibrary(hHookDll);
1232 if (hookRc == FALSE)
1234 if (bRunningAsService) {
1235 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1236 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1237 ServiceStatus.dwCheckPoint = 0;
1238 ServiceStatus.dwWaitHint = 0;
1239 ServiceStatus.dwControlsAccepted = 0;
1240 SetServiceStatus(StatusHandle, &ServiceStatus);
1242 /* exit if initialization failed */
1247 /* allow another 120 seconds to start */
1248 if (bRunningAsService) {
1249 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1250 ServiceStatus.dwServiceSpecificExitCode = 0;
1251 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1252 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1253 ServiceStatus.dwCheckPoint = 2;
1254 ServiceStatus.dwWaitHint = 120000;
1255 /* accept Power Events */
1256 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1257 SetServiceStatus(StatusHandle, &ServiceStatus);
1262 /* Perform Volume Status Notification Initialization */
1263 cm_VolStatus_Initialization();
1266 MainThreadId = GetCurrentThreadId();
1267 jmpret = setjmp(notifier_jmp);
1272 code = afsd_InitCM(&reason);
1274 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1275 osi_panic(reason, __FILE__, __LINE__);
1279 if (bRunningAsService) {
1280 ServiceStatus.dwCheckPoint = 3;
1281 ServiceStatus.dwWaitHint = 30000;
1282 SetServiceStatus(StatusHandle, &ServiceStatus);
1285 code = afsd_InitDaemons(&reason);
1287 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1288 osi_panic(reason, __FILE__, __LINE__);
1291 /* allow an exit to be called post rx initialization */
1292 hHookDll = cm_LoadAfsdHookLib();
1296 AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1299 hookRc = rxStartedHook();
1301 FreeLibrary(hHookDll);
1304 if (hookRc == FALSE)
1306 if (bRunningAsService) {
1307 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1308 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1309 ServiceStatus.dwCheckPoint = 0;
1310 ServiceStatus.dwWaitHint = 0;
1311 ServiceStatus.dwControlsAccepted = 0;
1312 SetServiceStatus(StatusHandle, &ServiceStatus);
1314 /* exit if initialization failed */
1320 if (bRunningAsService) {
1321 ServiceStatus.dwCheckPoint = 4;
1322 ServiceStatus.dwWaitHint = 15000;
1323 SetServiceStatus(StatusHandle, &ServiceStatus);
1327 /* Notify any volume status handlers that the cache manager has started */
1328 cm_VolStatus_Service_Started();
1330 /* the following ifdef chooses the mode of operation for the service. to enable
1331 * a runtime flag (instead of compile-time), pioctl() would need to dynamically
1332 * determine the mode, in order to use the correct ioctl special-file path. */
1333 code = afsd_InitSMB(&reason, MessageBox);
1335 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1336 osi_panic(reason, __FILE__, __LINE__);
1339 /* allow an exit to be called post smb initialization */
1340 hHookDll = cm_LoadAfsdHookLib();
1344 AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1347 hookRc = smbStartedHook();
1349 FreeLibrary(hHookDll);
1352 if (hookRc == FALSE)
1354 if (bRunningAsService) {
1355 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1356 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1357 ServiceStatus.dwCheckPoint = 0;
1358 ServiceStatus.dwWaitHint = 0;
1359 ServiceStatus.dwControlsAccepted = 0;
1360 SetServiceStatus(StatusHandle, &ServiceStatus);
1362 /* exit if initialization failed */
1367 MountGlobalDrives();
1370 if (bRunningAsService) {
1371 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1372 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1373 ServiceStatus.dwCheckPoint = 5;
1374 ServiceStatus.dwWaitHint = 0;
1376 /* accept Power events */
1377 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1378 SetServiceStatus(StatusHandle, &ServiceStatus);
1382 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1385 /* allow an exit to be called when started */
1386 hHookDll = cm_LoadAfsdHookLib();
1390 AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1393 hookRc = startedHook();
1395 FreeLibrary(hHookDll);
1398 if (hookRc == FALSE)
1400 if (bRunningAsService) {
1401 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1402 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1403 ServiceStatus.dwCheckPoint = 0;
1404 ServiceStatus.dwWaitHint = 0;
1405 ServiceStatus.dwControlsAccepted = 0;
1406 SetServiceStatus(StatusHandle, &ServiceStatus);
1408 /* exit if initialization failed */
1413 WaitForSingleObject(WaitToTerminate, INFINITE);
1415 if (bRunningAsService) {
1416 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1417 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1418 ServiceStatus.dwCheckPoint = 6;
1419 ServiceStatus.dwWaitHint = 120000;
1420 ServiceStatus.dwControlsAccepted = 0;
1421 SetServiceStatus(StatusHandle, &ServiceStatus);
1423 afsi_log("Received Termination Signal, Stopping Service");
1426 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP);
1428 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
1430 /* allow an exit to be called prior to stopping the service */
1431 hHookDll = cm_LoadAfsdHookLib();
1435 AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
1438 hookRc = stoppingHook();
1440 FreeLibrary(hHookDll);
1445 #ifdef AFS_FREELANCE_CLIENT
1446 cm_FreelanceShutdown();
1447 afsi_log("Freelance Shutdown complete");
1450 DismountGlobalDrives();
1451 afsi_log("Global Drives dismounted");
1454 afsi_log("smb shutdown complete");
1458 cm_ReleaseAllLocks();
1460 cm_DaemonShutdown();
1461 afsi_log("Daemon shutdown complete");
1464 afsi_log("Buffer shutdown complete");
1468 cm_ShutdownMappedMemory();
1471 afsi_log("rx finalization complete");
1473 #ifdef REGISTER_POWER_NOTIFICATIONS
1474 /* terminate thread used to flush cache */
1475 if (powerEventsRegistered)
1476 PowerNotificationThreadExit();
1481 cm_BPlusDumpStats();
1484 /* Notify any Volume Status Handlers that we are stopped */
1485 cm_VolStatus_Service_Stopped();
1487 /* Cleanup any Volume Status Notification Handler */
1488 cm_VolStatus_Finalize();
1490 /* allow an exit to be called after stopping the service */
1491 hHookDll = cm_LoadAfsdHookLib();
1495 AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1498 hookRc = stoppedHook();
1500 FreeLibrary(hHookDll);
1504 /* Remove the ExceptionFilter */
1505 SetUnhandledExceptionFilter(NULL);
1507 if (bRunningAsService) {
1508 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1509 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1510 ServiceStatus.dwCheckPoint = 7;
1511 ServiceStatus.dwWaitHint = 0;
1512 ServiceStatus.dwControlsAccepted = 0;
1513 SetServiceStatus(StatusHandle, &ServiceStatus);
1517 DWORD __stdcall afsdMain_thread(void* notUsed)
1519 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1520 afsd_Main(1, (LPTSTR*)argv);
1526 fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1530 main(int argc, char * argv[])
1532 static SERVICE_TABLE_ENTRY dispatchTable[] = {
1533 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1538 for (i = 1; i < argc; i++) {
1539 if (!stricmp(argv[i],"--validate-cache")) {
1540 if (++i != argc - 1) {
1545 return cm_ValidateMappedMemory(argv[i]);
1552 if (!StartServiceCtrlDispatcher(dispatchTable))
1554 LONG status = GetLastError();
1555 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1559 bRunningAsService = FALSE;
1561 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1563 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1565 SetEvent(WaitToTerminate);
1569 if ( hAFSDMainThread ) {
1570 WaitForSingleObject( hAFSDMainThread, INFINITE );
1571 CloseHandle( hAFSDMainThread );