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);
87 if (IsDebuggerPresent())
91 afsi_log("--- begin dump ---");
92 cm_MemDumpDirStats(afsi_file, "a", 0);
93 cm_MemDumpBPlusStats(afsi_file, "a", 0);
94 cm_DumpCells(afsi_file, "a", 0);
95 cm_DumpVolumes(afsi_file, "a", 0);
96 cm_DumpSCache(afsi_file, "a", 0);
97 cm_DumpBufHashTable(afsi_file, "a", 0);
98 cm_DumpServers(afsi_file, "a", 0);
99 smb_DumpVCP(afsi_file, "a", 0);
100 rx_DumpPackets(afsi_file, "a");
101 rx_DumpCalls(afsi_file, "a");
102 afsi_log("--- end dump ---");
104 GenerateMiniDump(NULL);
106 SetEvent(WaitToTerminate);
109 if (GetCurrentThreadId() == MainThreadId)
110 longjmp(notifier_jmp, 1);
113 if (bRunningAsService) {
114 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
115 ServiceStatus.dwWin32ExitCode = NO_ERROR;
116 ServiceStatus.dwCheckPoint = 0;
117 ServiceStatus.dwWaitHint = 0;
118 ServiceStatus.dwControlsAccepted = 0;
119 SetServiceStatus(StatusHandle, &ServiceStatus);
125 * For use miscellaneously in smb.c; need to do better
127 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
133 afsd_ServiceFlushVolume(DWORD dwlpEventData)
135 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
138 ** If UI bit is not set, user interaction is not possible
139 ** BUT, since we are a NON-interactive service, and therefore
140 ** have NO user I/O, it doesn't much matter.
141 ** This benign code left here as example of how to find this out
143 BOOL bUI = (dwlpEventData & 1);
146 if ( PowerNotificationThreadNotify() )
152 /* flush was unsuccessful, or timeout - deny shutdown */
153 dwRet = ERROR_NETWORK_BUSY;
156 /* to deny hibernate, simply return
157 // any value besides NO_ERROR.
159 // dwRet = ERROR_NETWORK_BUSY;
166 /* service control handler used in nt4 only for backward compat. */
168 afsd_ServiceControlHandler(DWORD ctrlCode)
171 DWORD dummyLen, doTrace;
175 case SERVICE_CONTROL_SHUTDOWN:
176 case SERVICE_CONTROL_STOP:
177 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
178 ServiceStatus.dwWin32ExitCode = NO_ERROR;
179 ServiceStatus.dwCheckPoint = 1;
180 ServiceStatus.dwWaitHint = 30000;
181 ServiceStatus.dwControlsAccepted = 0;
182 SetServiceStatus(StatusHandle, &ServiceStatus);
184 if (ctrlCode == SERVICE_CONTROL_STOP)
185 afsi_log("SERVICE_CONTROL_STOP");
187 afsi_log("SERVICE_CONTROL_SHUTDOWN");
189 /* Write all dirty buffers back to server */
190 if ( !lana_OnlyLoopback() )
193 /* Force trace if requested */
194 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
195 AFSREG_CLT_SVC_PARAM_SUBKEY,
196 0, KEY_QUERY_VALUE, &parmKey);
197 if (code != ERROR_SUCCESS)
200 dummyLen = sizeof(doTrace);
201 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
203 (BYTE *) &doTrace, &dummyLen);
204 RegCloseKey (parmKey);
205 if (code != ERROR_SUCCESS)
208 afsd_ForceTrace(FALSE);
209 buf_ForceTrace(FALSE);
213 SetEvent(WaitToTerminate);
216 case SERVICE_CONTROL_INTERROGATE:
217 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
218 ServiceStatus.dwWin32ExitCode = NO_ERROR;
219 ServiceStatus.dwCheckPoint = 0;
220 ServiceStatus.dwWaitHint = 0;
221 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
222 SetServiceStatus(StatusHandle, &ServiceStatus);
224 /* XXX handle system shutdown */
225 /* XXX handle pause & continue */
231 ** Extended ServiceControlHandler that provides Event types
232 ** for monitoring Power events, for example.
235 afsd_ServiceControlHandlerEx(
243 DWORD dummyLen, doTrace;
245 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
246 OSVERSIONINFO osVersion;
248 /* Get the version of Windows */
249 memset(&osVersion, 0x00, sizeof(osVersion));
250 osVersion.dwOSVersionInfoSize = sizeof(osVersion);
251 GetVersionEx(&osVersion);
255 case SERVICE_CONTROL_SHUTDOWN:
256 case SERVICE_CONTROL_STOP:
257 if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
258 afsi_log("SERVICE_CONTROL_SHUTDOWN");
260 afsi_log("SERVICE_CONTROL_STOP");
262 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
263 ServiceStatus.dwWin32ExitCode = NO_ERROR;
264 ServiceStatus.dwCheckPoint = 1;
265 ServiceStatus.dwWaitHint = 30000;
266 ServiceStatus.dwControlsAccepted = 0;
267 SetServiceStatus(StatusHandle, &ServiceStatus);
269 /* Write all dirty buffers back to server */
270 if ( !lana_OnlyLoopback() )
273 /* Force trace if requested */
274 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
275 AFSREG_CLT_SVC_PARAM_SUBKEY,
276 0, KEY_QUERY_VALUE, &parmKey);
277 if (code != ERROR_SUCCESS)
280 dummyLen = sizeof(doTrace);
281 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
283 (BYTE *) &doTrace, &dummyLen);
284 RegCloseKey (parmKey);
285 if (code != ERROR_SUCCESS)
288 afsd_ForceTrace(FALSE);
289 buf_ForceTrace(FALSE);
293 SetEvent(WaitToTerminate);
297 case SERVICE_CONTROL_INTERROGATE:
298 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
299 ServiceStatus.dwWin32ExitCode = NO_ERROR;
300 ServiceStatus.dwCheckPoint = 0;
301 ServiceStatus.dwWaitHint = 0;
302 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
303 SetServiceStatus(StatusHandle, &ServiceStatus);
304 afsi_log("SERVICE_CONTROL_INTERROGATE");
308 /* XXX handle system shutdown */
309 /* XXX handle pause & continue */
310 case SERVICE_CONTROL_POWEREVENT:
313 afsi_log("SERVICE_CONTROL_POWEREVENT");
316 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
317 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
318 ** Return any error code to deny request,
319 ** i.e. as if returning BROADCAST_QUERY_DENY
321 if (powerEventsRegistered) {
322 switch((int) dwEventType)
324 case PBT_APMQUERYSUSPEND:
325 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND");
326 /* Write all dirty buffers back to server */
327 if ( !lana_OnlyLoopback() ) {
331 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete");
334 case PBT_APMQUERYSTANDBY:
335 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY");
336 /* Write all dirty buffers back to server */
337 if ( !lana_OnlyLoopback() ) {
341 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete");
345 /* allow remaining case PBT_WhatEver */
347 afsi_log("SERVICE_CONTROL_APMSUSPEND");
348 powerStateSuspended = 1;
349 if (osVersion.dwMajorVersion >= 6) {
351 smb_StopListeners(0);
356 afsi_log("SERVICE_CONTROL_APMSTANDBY");
357 powerStateSuspended = 1;
358 if (osVersion.dwMajorVersion >= 6) {
360 smb_StopListeners(0);
364 case PBT_APMRESUMECRITICAL:
365 afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL");
366 if (osVersion.dwMajorVersion >= 6)
367 smb_RestartListeners(0);
370 case PBT_APMRESUMESUSPEND:
371 /* User logged in after suspend */
372 afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND");
375 case PBT_APMRESUMESTANDBY:
376 /* User logged in after standby */
377 afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY");
380 case PBT_APMBATTERYLOW:
381 afsi_log("SERVICE_CONTROL_APMBATTERYLOW");
384 case PBT_APMPOWERSTATUSCHANGE:
386 afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
390 case PBT_APMOEMEVENT:
392 afsi_log("SERVICE_CONTROL_APMOEMEVENT");
396 case PBT_APMRESUMEAUTOMATIC:
397 /* This is the message delivered once all devices are up */
398 afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC");
399 powerStateSuspended = 0;
400 if (osVersion.dwMajorVersion >= 6) {
401 smb_SetLanAdapterChangeDetected();
406 afsi_log("SERVICE_CONTROL_unknown");
412 case SERVICE_CONTROL_CUSTOM_DUMP:
414 afsi_log("SERVICE_CONTROL_CUSTOM_DUMP");
415 GenerateMiniDump(NULL);
419 } /* end switch(ctrlCode) */
423 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
425 * Mount a drive into AFS if there global mapping
427 /* DEE Could check first if we are run as SYSTEM */
428 #define MAX_RETRIES 10
429 #define MAX_DRIVES 23
430 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
432 char szAfsPath[_MAX_PATH];
433 char szDriveToMapTo[5];
437 DWORD dwIndex = 0, dwRetry = 0;
439 DWORD dwSubMountSize;
440 char szSubMount[256];
443 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
445 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
446 if (dwResult != ERROR_SUCCESS)
449 while (dwIndex < MAX_DRIVES) {
450 dwDriveSize = sizeof(szDriveToMapTo);
451 dwSubMountSize = sizeof(szSubMount);
452 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
453 if (dwResult != ERROR_MORE_DATA) {
454 if (dwResult != ERROR_SUCCESS) {
455 if (dwResult != ERROR_NO_MORE_ITEMS)
456 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
461 for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
464 memset (&nr, 0x00, sizeof(NETRESOURCE));
466 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
468 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
469 nr.dwType=RESOURCETYPE_DISK;
470 nr.lpLocalName=strlen(szDriveToMapTo) > 0 ? szDriveToMapTo : NULL;
471 nr.lpRemoteName=szAfsPath;
472 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
473 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
475 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
476 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
477 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
478 if (dwResult == NO_ERROR) {
481 /* wait for smb server to come up */
482 Sleep((DWORD)1000 /* miliseconds */);
484 /* Disconnect any previous mappings */
485 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
493 static HANDLE hThreadMountGlobalDrives = NULL;
495 static void MountGlobalDrives()
499 hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
501 if ( hThreadMountGlobalDrives ) {
502 DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
503 if (rc == WAIT_TIMEOUT) {
504 afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
505 } else if (rc == WAIT_OBJECT_0) {
506 afsi_log("GlobalAutoMap thread completed");
507 CloseHandle( hThreadMountGlobalDrives );
508 hThreadMountGlobalDrives = NULL;
513 static void DismountGlobalDrives()
515 char szAfsPath[_MAX_PATH];
516 char szDriveToMapTo[5];
518 DWORD dwSubMountSize;
519 char szSubMount[256];
526 if ( hThreadMountGlobalDrives ) {
527 DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
529 if (rc == WAIT_TIMEOUT) {
530 afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
532 else if (rc == WAIT_OBJECT_0) {
533 afsi_log("GlobalAutoMap thread completed");
534 CloseHandle( hThreadMountGlobalDrives );
535 hThreadMountGlobalDrives = NULL;
539 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
541 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
542 if (dwResult != ERROR_SUCCESS)
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");
569 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
571 DWORD dwVersionHandle;
572 LPVOID pVersionInfo = 0;
574 LPDWORD pLangInfo = 0;
575 LPTSTR szVersion = 0;
577 TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
578 DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
581 afsi_log("GetFileVersionInfoSize failed");
582 return GetLastError();
585 pVersionInfo = malloc(size);
587 afsi_log("out of memory 1");
588 return ERROR_NOT_ENOUGH_MEMORY;
591 GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
592 if (retval = GetLastError())
594 afsi_log("GetFileVersionInfo failed: %d", retval);
598 VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
599 (LPVOID*)&pLangInfo, &len);
600 if (retval = GetLastError())
602 afsi_log("VerQueryValue 1 failed: %d", retval);
607 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
608 LOWORD(*pLangInfo), HIWORD(*pLangInfo));
610 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
611 if (retval = GetLastError())
613 /* try again with language 409 since the old binaries were tagged wrong */
615 TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
618 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
619 if (retval = GetLastError()) {
620 afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
624 snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
625 szOutput[dwOutput - 1] = 0;
634 static HINSTANCE hCrypt32;
635 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags,
636 void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
637 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
638 DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
639 DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
640 DWORD* pdwFormatType, HCERTSTORE* phCertStore,
641 HCRYPTMSG* phMsg, const void** ppvContext);
642 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
643 void* pvData, DWORD* pcbData);
644 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
645 DWORD dwFindFlags, DWORD dwFindType,
646 const void* pvFindPara,
647 PCCERT_CONTEXT pPrevCertContext);
648 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
649 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
650 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
651 PCERT_INFO pCertId2);
652 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
654 void LoadCrypt32(void)
656 hCrypt32 = LoadLibrary("crypt32");
660 (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
661 (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
662 (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
663 (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
664 (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
665 (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
666 (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
667 (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
669 if ( !pCertGetNameString ||
670 !pCryptQueryObject ||
671 !pCryptMsgGetParam ||
672 !pCertFindCertificateInStore ||
675 !pCertCompareCertificate ||
676 !pCertFreeCertificateContext)
678 FreeLibrary(hCrypt32);
683 void UnloadCrypt32(void)
685 FreeLibrary(hCrypt32);
688 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
690 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
692 wchar_t wfilename[260];
698 HCERTSTORE hStore = NULL;
699 HCRYPTMSG hMsg = NULL;
700 PCMSG_SIGNER_INFO pSignerInfo = NULL;
701 PCCERT_CONTEXT pCertContext = NULL;
704 if ( hCrypt32 == NULL )
707 ZeroMemory(&CertInfo, sizeof(CertInfo));
708 mbstowcs(wfilename, filename, 260);
710 fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
712 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
713 CERT_QUERY_FORMAT_FLAG_BINARY,
723 afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
729 fResult = pCryptMsgGetParam(hMsg,
730 CMSG_SIGNER_INFO_PARAM,
736 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
742 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
744 fResult = pCryptMsgGetParam(hMsg,
745 CMSG_SIGNER_INFO_PARAM,
751 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
757 CertInfo.Issuer = pSignerInfo->Issuer;
758 CertInfo.SerialNumber = pSignerInfo->SerialNumber;
760 pCertContext = pCertFindCertificateInStore(hStore,
763 CERT_FIND_SUBJECT_CERT,
768 afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
776 LocalFree(pSignerInfo);
779 CertFreeCertificateContext(pCertContext);*/
782 pCertCloseStore(hStore,0);
785 pCryptMsgClose(hMsg);
790 BOOL VerifyTrust(CHAR * filename)
792 WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
793 WIN_TRUST_SUBJECT_FILE fSubjectFile;
794 GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
795 GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
796 wchar_t wfilename[260];
798 BOOL success = FALSE;
800 LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
803 if (filename == NULL )
806 hWinTrust = LoadLibrary("wintrust");
810 if (((FARPROC) pWinVerifyTrust =
811 GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
813 FreeLibrary(hWinTrust);
817 mbstowcs(wfilename, filename, 260);
819 fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
821 fSubjectFile.lpPath = wfilename;
822 fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
823 FALSE, GetCurrentProcessId());
824 fContextWSubject.SubjectType = &subject;
825 fContextWSubject.Subject = &fSubjectFile;
827 ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
829 if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
830 CloseHandle( fSubjectFile.hFile );
831 if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
832 CloseHandle( fContextWSubject.hClientToken );
834 if (ret == ERROR_SUCCESS) {
837 DWORD gle = GetLastError();
839 case TRUST_E_PROVIDER_UNKNOWN:
840 afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
842 case TRUST_E_NOSIGNATURE:
843 afsi_log("VerifyTrust failed: Unsigned executable");
845 case TRUST_E_EXPLICIT_DISTRUST:
846 afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
848 case TRUST_E_SUBJECT_NOT_TRUSTED:
849 afsi_log("VerifyTrust failed: File is not trusted");
851 case TRUST_E_BAD_DIGEST:
852 afsi_log("VerifyTrust failed: Executable has been modified");
854 case CRYPT_E_SECURITY_SETTINGS:
855 afsi_log("VerifyTrust failed: local security options prevent verification");
858 afsi_log("VerifyTrust failed: 0x%X", GetLastError());
862 FreeLibrary(hWinTrust);
866 void LogCertCtx(PCCERT_CONTEXT pCtx) {
868 LPTSTR szName = NULL;
870 if ( hCrypt32 == NULL )
873 // Get Issuer name size.
874 if (!(dwData = pCertGetNameString(pCtx,
875 CERT_NAME_SIMPLE_DISPLAY_TYPE,
876 CERT_NAME_ISSUER_FLAG,
880 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
884 // Allocate memory for Issuer name.
885 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
888 if (!(pCertGetNameString(pCtx,
889 CERT_NAME_SIMPLE_DISPLAY_TYPE,
890 CERT_NAME_ISSUER_FLAG,
894 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
898 // print Issuer name.
899 afsi_log("Issuer Name: %s", szName);
903 // Get Subject name size.
904 if (!(dwData = pCertGetNameString(pCtx,
905 CERT_NAME_SIMPLE_DISPLAY_TYPE,
910 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
914 // Allocate memory for subject name.
915 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
918 if (!(pCertGetNameString(pCtx,
919 CERT_NAME_SIMPLE_DISPLAY_TYPE,
924 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
928 // Print Subject Name.
929 afsi_log("Subject Name: %s", szName);
937 BOOL AFSModulesVerify(void)
940 CHAR afsdVersion[128];
941 CHAR modVersion[128];
942 CHAR checkName[1024];
943 BOOL trustVerified = FALSE;
949 PCCERT_CONTEXT pCtxService = NULL;
951 DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
952 BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
953 DWORD dummyLen, code;
954 DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
955 DWORD verifyServiceSig = TRUE;
958 hPSAPI = LoadLibrary("psapi");
960 if ( hPSAPI == NULL )
963 if (!GetModuleFileName(NULL, filename, sizeof(filename)))
966 if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
969 afsi_log("%s version %s", filename, afsdVersion);
971 if (((FARPROC) pGetModuleFileNameExA =
972 GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
973 ((FARPROC) pEnumProcessModules =
974 GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
981 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
982 AFSREG_CLT_SVC_PARAM_SUBKEY,
983 0, KEY_QUERY_VALUE, &parmKey);
984 if (code == ERROR_SUCCESS) {
985 dummyLen = sizeof(cacheSize);
986 code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
987 (BYTE *) &cacheSize, &dummyLen);
988 RegCloseKey (parmKey);
991 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
992 0, KEY_QUERY_VALUE, &parmKey);
993 if (code == ERROR_SUCCESS) {
994 dummyLen = sizeof(verifyServiceSig);
995 code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
996 (BYTE *) &verifyServiceSig, &dummyLen);
997 RegCloseKey (parmKey);
1000 if (verifyServiceSig
1002 && cacheSize < 716800
1005 trustVerified = VerifyTrust(filename);
1007 afsi_log("Signature Verification disabled");
1010 if (trustVerified) {
1013 // get a certificate context for the signer of afsd_service.
1014 pCtxService = GetCertCtx(filename);
1016 LogCertCtx(pCtxService);
1019 // Get a list of all the modules in this process.
1020 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1021 FALSE, GetCurrentProcessId());
1023 if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1025 afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1027 for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1029 char szModName[2048];
1031 // Get the full path to the module's file.
1032 if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1034 lstrcpy(checkName, szModName);
1037 if ( strstr(checkName, "afspthread.dll") ||
1038 strstr(checkName, "afsauthent.dll") ||
1039 strstr(checkName, "afsrpc.dll") ||
1040 strstr(checkName, "libafsconf.dll") ||
1041 strstr(checkName, "libosi.dll") )
1043 if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1048 afsi_log("%s version %s", szModName, modVersion);
1049 if (strcmp(afsdVersion,modVersion)) {
1050 afsi_log("Version mismatch: %s", szModName);
1053 if ( trustVerified ) {
1054 if ( !VerifyTrust(szModName) ) {
1055 afsi_log("Signature Verification failed: %s", szModName);
1058 else if (pCtxService) {
1059 PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1061 if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1062 pCtxService->pCertInfo,
1064 afsi_log("Certificate mismatch: %s", szModName);
1072 pCertFreeCertificateContext(pCtx);
1081 pCertFreeCertificateContext(pCtxService);
1085 FreeLibrary(hPSAPI);
1087 CloseHandle(hProcess);
1092 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1095 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1096 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
1098 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1099 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
1102 afsd_Main(DWORD argc, LPTSTR *argv)
1114 void afsd_DbgBreakAllocInit();
1116 afsd_DbgBreakAllocInit();
1117 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
1118 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1121 afsd_SetUnhandledExceptionFilter();
1123 osi_InitPanic(afsd_notifier);
1124 osi_InitTraceOption();
1126 hKernel32 = LoadLibrary("kernel32.dll");
1127 if (hKernel32 == NULL)
1129 afsi_log("Fatal: cannot load kernel32.dll");
1132 pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
1138 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1139 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1140 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1143 hAdvApi32 = LoadLibrary("advapi32.dll");
1144 if (hAdvApi32 == NULL)
1146 afsi_log("Fatal: cannot load advapi32.dll");
1150 if (bRunningAsService) {
1151 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
1152 if (pRegisterServiceCtrlHandlerEx)
1154 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
1155 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
1159 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
1162 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1163 ServiceStatus.dwServiceSpecificExitCode = 0;
1164 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1165 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1166 ServiceStatus.dwCheckPoint = 1;
1167 ServiceStatus.dwWaitHint = 120000;
1168 /* accept Power Events */
1169 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1170 SetServiceStatus(StatusHandle, &ServiceStatus);
1174 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
1176 #ifdef REGISTER_POWER_NOTIFICATIONS
1183 /* see if we should handle power notifications */
1184 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1185 0, KEY_QUERY_VALUE, &hkParm);
1186 if (code == ERROR_SUCCESS) {
1187 dummyLen = sizeof(bpower);
1188 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
1189 (BYTE *) &bpower, &dummyLen);
1191 if(code != ERROR_SUCCESS)
1194 RegCloseKey(hkParm);
1196 /* create thread used to flush cache */
1198 PowerNotificationThreadCreate();
1199 powerEventsRegistered = 1;
1204 /* Verify the versions of the DLLs which were loaded */
1205 if (!AFSModulesVerify()) {
1206 if (bRunningAsService) {
1207 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1208 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1209 ServiceStatus.dwCheckPoint = 0;
1210 ServiceStatus.dwWaitHint = 0;
1211 ServiceStatus.dwControlsAccepted = 0;
1212 SetServiceStatus(StatusHandle, &ServiceStatus);
1214 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1216 /* exit if initialization failed */
1220 /* allow an exit to be called prior to any initialization */
1221 hHookDll = cm_LoadAfsdHookLib();
1225 AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1228 hookRc = initHook();
1230 FreeLibrary(hHookDll);
1233 if (hookRc == FALSE)
1235 if (bRunningAsService) {
1236 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1237 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1238 ServiceStatus.dwCheckPoint = 0;
1239 ServiceStatus.dwWaitHint = 0;
1240 ServiceStatus.dwControlsAccepted = 0;
1241 SetServiceStatus(StatusHandle, &ServiceStatus);
1243 /* exit if initialization failed */
1248 /* allow another 120 seconds to start */
1249 if (bRunningAsService) {
1250 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1251 ServiceStatus.dwServiceSpecificExitCode = 0;
1252 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1253 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1254 ServiceStatus.dwCheckPoint = 2;
1255 ServiceStatus.dwWaitHint = 120000;
1256 /* accept Power Events */
1257 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1258 SetServiceStatus(StatusHandle, &ServiceStatus);
1263 /* Perform Volume Status Notification Initialization */
1264 cm_VolStatus_Initialization();
1267 MainThreadId = GetCurrentThreadId();
1268 jmpret = setjmp(notifier_jmp);
1273 code = afsd_InitCM(&reason);
1275 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1276 osi_panic(reason, __FILE__, __LINE__);
1280 if (bRunningAsService) {
1281 ServiceStatus.dwCheckPoint = 3;
1282 ServiceStatus.dwWaitHint = 30000;
1283 SetServiceStatus(StatusHandle, &ServiceStatus);
1286 /* allow an exit to be called post rx initialization */
1287 hHookDll = cm_LoadAfsdHookLib();
1291 AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1294 hookRc = rxStartedHook();
1296 FreeLibrary(hHookDll);
1299 if (hookRc == FALSE)
1301 if (bRunningAsService) {
1302 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1303 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1304 ServiceStatus.dwCheckPoint = 0;
1305 ServiceStatus.dwWaitHint = 0;
1306 ServiceStatus.dwControlsAccepted = 0;
1307 SetServiceStatus(StatusHandle, &ServiceStatus);
1309 /* exit if initialization failed */
1315 if (bRunningAsService) {
1316 ServiceStatus.dwCheckPoint = 4;
1317 ServiceStatus.dwWaitHint = 15000;
1318 SetServiceStatus(StatusHandle, &ServiceStatus);
1322 /* Notify any volume status handlers that the cache manager has started */
1323 cm_VolStatus_Service_Started();
1325 code = afsd_InitSMB(&reason, MessageBox);
1327 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1328 osi_panic(reason, __FILE__, __LINE__);
1331 /* allow an exit to be called post smb initialization */
1332 hHookDll = cm_LoadAfsdHookLib();
1336 AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1339 hookRc = smbStartedHook();
1341 FreeLibrary(hHookDll);
1344 if (hookRc == FALSE)
1346 if (bRunningAsService) {
1347 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1348 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1349 ServiceStatus.dwCheckPoint = 0;
1350 ServiceStatus.dwWaitHint = 0;
1351 ServiceStatus.dwControlsAccepted = 0;
1352 SetServiceStatus(StatusHandle, &ServiceStatus);
1354 /* exit if initialization failed */
1359 MountGlobalDrives();
1361 code = afsd_InitDaemons(&reason);
1363 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1364 osi_panic(reason, __FILE__, __LINE__);
1368 if (bRunningAsService) {
1369 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1370 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1371 ServiceStatus.dwCheckPoint = 5;
1372 ServiceStatus.dwWaitHint = 0;
1374 /* accept Power events */
1375 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1376 SetServiceStatus(StatusHandle, &ServiceStatus);
1380 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1383 /* allow an exit to be called when started */
1384 hHookDll = cm_LoadAfsdHookLib();
1388 AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1391 hookRc = startedHook();
1393 FreeLibrary(hHookDll);
1396 if (hookRc == FALSE)
1398 if (bRunningAsService) {
1399 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1400 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1401 ServiceStatus.dwCheckPoint = 0;
1402 ServiceStatus.dwWaitHint = 0;
1403 ServiceStatus.dwControlsAccepted = 0;
1404 SetServiceStatus(StatusHandle, &ServiceStatus);
1406 /* exit if initialization failed */
1411 WaitForSingleObject(WaitToTerminate, INFINITE);
1413 if (bRunningAsService) {
1414 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1415 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1416 ServiceStatus.dwCheckPoint = 6;
1417 ServiceStatus.dwWaitHint = 120000;
1418 ServiceStatus.dwControlsAccepted = 0;
1419 SetServiceStatus(StatusHandle, &ServiceStatus);
1421 afsi_log("Received Termination Signal, Stopping Service");
1424 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP);
1426 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
1428 /* allow an exit to be called prior to stopping the service */
1429 hHookDll = cm_LoadAfsdHookLib();
1433 AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
1436 hookRc = stoppingHook();
1438 FreeLibrary(hHookDll);
1443 #ifdef AFS_FREELANCE_CLIENT
1444 cm_FreelanceShutdown();
1445 afsi_log("Freelance Shutdown complete");
1448 DismountGlobalDrives();
1449 afsi_log("Global Drives dismounted");
1452 afsi_log("smb shutdown complete");
1456 cm_ReleaseAllLocks();
1458 cm_DaemonShutdown();
1459 afsi_log("Daemon shutdown complete");
1462 afsi_log("Buffer shutdown complete");
1466 cm_ShutdownMappedMemory();
1469 afsi_log("rx finalization complete");
1471 #ifdef REGISTER_POWER_NOTIFICATIONS
1472 /* terminate thread used to flush cache */
1473 if (powerEventsRegistered)
1474 PowerNotificationThreadExit();
1479 cm_BPlusDumpStats();
1482 /* Notify any Volume Status Handlers that we are stopped */
1483 cm_VolStatus_Service_Stopped();
1485 /* Cleanup any Volume Status Notification Handler */
1486 cm_VolStatus_Finalize();
1488 /* allow an exit to be called after stopping the service */
1489 hHookDll = cm_LoadAfsdHookLib();
1493 AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1496 hookRc = stoppedHook();
1498 FreeLibrary(hHookDll);
1502 /* Remove the ExceptionFilter */
1503 SetUnhandledExceptionFilter(NULL);
1505 if (bRunningAsService) {
1506 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1507 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1508 ServiceStatus.dwCheckPoint = 7;
1509 ServiceStatus.dwWaitHint = 0;
1510 ServiceStatus.dwControlsAccepted = 0;
1511 SetServiceStatus(StatusHandle, &ServiceStatus);
1515 DWORD __stdcall afsdMain_thread(void* notUsed)
1517 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1518 afsd_Main(1, (LPTSTR*)argv);
1524 fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1528 main(int argc, char * argv[])
1530 static SERVICE_TABLE_ENTRY dispatchTable[] = {
1531 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1536 for (i = 1; i < argc; i++) {
1537 if (!stricmp(argv[i],"--validate-cache")) {
1538 if (++i != argc - 1) {
1543 return cm_ValidateMappedMemory(argv[i]);
1550 if (!StartServiceCtrlDispatcher(dispatchTable))
1552 LONG status = GetLastError();
1553 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1557 bRunningAsService = FALSE;
1559 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1561 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1563 SetEvent(WaitToTerminate);
1567 if ( hAFSDMainThread ) {
1568 WaitForSingleObject( hAFSDMainThread, INFINITE );
1569 CloseHandle( hAFSDMainThread );