15 #include "afsd_init.h"
16 #include "lanahelper.h"
20 #include <WINNT\afsreg.h>
34 //#define REGISTER_POWER_NOTIFICATIONS 1
35 #include "afsd_flushvol.h"
37 extern void afsi_log(char *pattern, ...);
39 static SERVICE_STATUS ServiceStatus;
40 static SERVICE_STATUS_HANDLE StatusHandle;
41 static BOOL bRunningAsService = TRUE;
43 HANDLE hAFSDMainThread = NULL;
45 HANDLE WaitToTerminate;
47 static int GlobalStatus;
50 unsigned int MainThreadId;
54 extern int traceOnPanic;
55 extern HANDLE afsi_file;
57 static int powerEventsRegistered = 0;
58 extern int powerStateSuspended = 0;
60 static VOID (WINAPI* pRtlCaptureContext)(PCONTEXT ContextRecord) = NULL;
63 * Notifier function for use by osi_panic
65 static void afsd_notifier(char *msgp, char *filep, long line)
70 msgp = "unspecified assert";
73 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION,
76 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG, msgp);
80 osi_LogEnable(afsd_logp);
82 afsd_ForceTrace(TRUE);
85 if (pRtlCaptureContext) {
86 pRtlCaptureContext(&context);
87 afsd_printStack(GetCurrentThread(), &context);
91 if (IsDebuggerPresent())
95 afsi_log("--- begin dump ---");
96 cm_MemDumpDirStats(afsi_file, "a", 0);
97 cm_MemDumpBPlusStats(afsi_file, "a", 0);
98 cm_DumpCells(afsi_file, "a", 0);
99 cm_DumpVolumes(afsi_file, "a", 0);
100 cm_DumpSCache(afsi_file, "a", 0);
101 cm_DumpBufHashTable(afsi_file, "a", 0);
102 cm_DumpServers(afsi_file, "a", 0);
103 smb_DumpVCP(afsi_file, "a", 0);
104 rx_DumpPackets(afsi_file, "a");
105 rx_DumpCalls(afsi_file, "a");
106 afsi_log("--- end dump ---");
108 GenerateMiniDump(NULL);
110 SetEvent(WaitToTerminate);
113 if (GetCurrentThreadId() == MainThreadId)
114 longjmp(notifier_jmp, 1);
117 if (bRunningAsService) {
118 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
119 ServiceStatus.dwWin32ExitCode = NO_ERROR;
120 ServiceStatus.dwCheckPoint = 0;
121 ServiceStatus.dwWaitHint = 0;
122 ServiceStatus.dwControlsAccepted = 0;
123 SetServiceStatus(StatusHandle, &ServiceStatus);
129 * For use miscellaneously in smb.c; need to do better
131 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
137 afsd_ServiceFlushVolume(DWORD dwlpEventData)
139 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
142 ** If UI bit is not set, user interaction is not possible
143 ** BUT, since we are a NON-interactive service, and therefore
144 ** have NO user I/O, it doesn't much matter.
145 ** This benign code left here as example of how to find this out
147 BOOL bUI = (dwlpEventData & 1);
150 if ( PowerNotificationThreadNotify() )
156 /* flush was unsuccessful, or timeout - deny shutdown */
157 dwRet = ERROR_NETWORK_BUSY;
160 /* to deny hibernate, simply return
161 // any value besides NO_ERROR.
163 // dwRet = ERROR_NETWORK_BUSY;
170 /* service control handler used in nt4 only for backward compat. */
172 afsd_ServiceControlHandler(DWORD ctrlCode)
175 DWORD dummyLen, doTrace;
179 case SERVICE_CONTROL_SHUTDOWN:
180 case SERVICE_CONTROL_STOP:
181 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
182 ServiceStatus.dwWin32ExitCode = NO_ERROR;
183 ServiceStatus.dwCheckPoint = 1;
184 ServiceStatus.dwWaitHint = 30000;
185 ServiceStatus.dwControlsAccepted = 0;
186 SetServiceStatus(StatusHandle, &ServiceStatus);
188 if (ctrlCode == SERVICE_CONTROL_STOP)
189 afsi_log("SERVICE_CONTROL_STOP");
191 afsi_log("SERVICE_CONTROL_SHUTDOWN");
193 /* Write all dirty buffers back to server */
194 if ( !lana_OnlyLoopback() )
197 /* Force trace if requested */
198 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
199 AFSREG_CLT_SVC_PARAM_SUBKEY,
200 0, KEY_QUERY_VALUE, &parmKey);
201 if (code != ERROR_SUCCESS)
204 dummyLen = sizeof(doTrace);
205 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
207 (BYTE *) &doTrace, &dummyLen);
208 RegCloseKey (parmKey);
209 if (code != ERROR_SUCCESS)
212 afsd_ForceTrace(FALSE);
213 buf_ForceTrace(FALSE);
217 SetEvent(WaitToTerminate);
220 case SERVICE_CONTROL_INTERROGATE:
221 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
222 ServiceStatus.dwWin32ExitCode = NO_ERROR;
223 ServiceStatus.dwCheckPoint = 0;
224 ServiceStatus.dwWaitHint = 0;
225 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
226 SetServiceStatus(StatusHandle, &ServiceStatus);
228 /* XXX handle system shutdown */
229 /* XXX handle pause & continue */
235 ** Extended ServiceControlHandler that provides Event types
236 ** for monitoring Power events, for example.
239 afsd_ServiceControlHandlerEx(
247 DWORD dummyLen, doTrace;
249 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
250 OSVERSIONINFO osVersion;
252 /* Get the version of Windows */
253 memset(&osVersion, 0x00, sizeof(osVersion));
254 osVersion.dwOSVersionInfoSize = sizeof(osVersion);
255 GetVersionEx(&osVersion);
259 case SERVICE_CONTROL_SHUTDOWN:
260 case SERVICE_CONTROL_STOP:
261 if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
262 afsi_log("SERVICE_CONTROL_SHUTDOWN");
264 afsi_log("SERVICE_CONTROL_STOP");
266 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
267 ServiceStatus.dwWin32ExitCode = NO_ERROR;
268 ServiceStatus.dwCheckPoint = 1;
269 ServiceStatus.dwWaitHint = 30000;
270 ServiceStatus.dwControlsAccepted = 0;
271 SetServiceStatus(StatusHandle, &ServiceStatus);
273 /* Write all dirty buffers back to server */
274 if ( !lana_OnlyLoopback() )
277 /* Force trace if requested */
278 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
279 AFSREG_CLT_SVC_PARAM_SUBKEY,
280 0, KEY_QUERY_VALUE, &parmKey);
281 if (code != ERROR_SUCCESS)
284 dummyLen = sizeof(doTrace);
285 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
287 (BYTE *) &doTrace, &dummyLen);
288 RegCloseKey (parmKey);
289 if (code != ERROR_SUCCESS)
292 afsd_ForceTrace(FALSE);
293 buf_ForceTrace(FALSE);
297 SetEvent(WaitToTerminate);
301 case SERVICE_CONTROL_INTERROGATE:
302 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
303 ServiceStatus.dwWin32ExitCode = NO_ERROR;
304 ServiceStatus.dwCheckPoint = 0;
305 ServiceStatus.dwWaitHint = 0;
306 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
307 SetServiceStatus(StatusHandle, &ServiceStatus);
308 afsi_log("SERVICE_CONTROL_INTERROGATE");
312 /* XXX handle system shutdown */
313 /* XXX handle pause & continue */
314 case SERVICE_CONTROL_POWEREVENT:
317 afsi_log("SERVICE_CONTROL_POWEREVENT");
320 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
321 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
322 ** Return any error code to deny request,
323 ** i.e. as if returning BROADCAST_QUERY_DENY
325 if (powerEventsRegistered) {
326 switch((int) dwEventType)
328 case PBT_APMQUERYSUSPEND:
329 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND");
330 /* Write all dirty buffers back to server */
331 if ( !lana_OnlyLoopback() ) {
335 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete");
338 case PBT_APMQUERYSTANDBY:
339 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY");
340 /* Write all dirty buffers back to server */
341 if ( !lana_OnlyLoopback() ) {
345 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete");
349 /* allow remaining case PBT_WhatEver */
351 afsi_log("SERVICE_CONTROL_APMSUSPEND");
352 powerStateSuspended = 1;
353 if (osVersion.dwMajorVersion >= 6) {
355 smb_StopListeners(0);
360 afsi_log("SERVICE_CONTROL_APMSTANDBY");
361 powerStateSuspended = 1;
362 if (osVersion.dwMajorVersion >= 6) {
364 smb_StopListeners(0);
368 case PBT_APMRESUMECRITICAL:
369 afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL");
370 if (osVersion.dwMajorVersion >= 6)
371 smb_RestartListeners(0);
374 case PBT_APMRESUMESUSPEND:
375 /* User logged in after suspend */
376 afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND");
379 case PBT_APMRESUMESTANDBY:
380 /* User logged in after standby */
381 afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY");
384 case PBT_APMBATTERYLOW:
385 afsi_log("SERVICE_CONTROL_APMBATTERYLOW");
388 case PBT_APMPOWERSTATUSCHANGE:
390 afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
394 case PBT_APMOEMEVENT:
396 afsi_log("SERVICE_CONTROL_APMOEMEVENT");
400 case PBT_APMRESUMEAUTOMATIC:
401 /* This is the message delivered once all devices are up */
402 afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC");
403 powerStateSuspended = 0;
404 if (osVersion.dwMajorVersion >= 6) {
405 smb_SetLanAdapterChangeDetected();
410 afsi_log("SERVICE_CONTROL_unknown");
416 case SERVICE_CONTROL_CUSTOM_DUMP:
418 afsi_log("SERVICE_CONTROL_CUSTOM_DUMP");
419 GenerateMiniDump(NULL);
423 } /* end switch(ctrlCode) */
427 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
429 * Mount a drive into AFS if there global mapping
431 /* DEE Could check first if we are run as SYSTEM */
432 #define MAX_RETRIES 10
433 #define MAX_DRIVES 23
434 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
436 char szAfsPath[_MAX_PATH];
437 char szDriveToMapTo[5];
441 DWORD dwIndex = 0, dwRetry = 0;
443 DWORD dwSubMountSize;
444 char szSubMount[256];
447 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
449 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
450 if (dwResult != ERROR_SUCCESS)
453 while (dwIndex < MAX_DRIVES) {
454 dwDriveSize = sizeof(szDriveToMapTo);
455 dwSubMountSize = sizeof(szSubMount);
456 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
457 if (dwResult != ERROR_MORE_DATA) {
458 if (dwResult != ERROR_SUCCESS) {
459 if (dwResult != ERROR_NO_MORE_ITEMS)
460 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
465 for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
468 memset (&nr, 0x00, sizeof(NETRESOURCE));
470 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
472 nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */
473 nr.dwType=RESOURCETYPE_DISK;
474 nr.lpLocalName=strlen(szDriveToMapTo) > 0 ? szDriveToMapTo : NULL;
475 nr.lpRemoteName=szAfsPath;
476 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
477 nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */
479 dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
480 afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount,
481 (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
482 if (dwResult == NO_ERROR) {
485 /* wait for smb server to come up */
486 Sleep((DWORD)1000 /* miliseconds */);
488 /* Disconnect any previous mappings */
489 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
497 static HANDLE hThreadMountGlobalDrives = NULL;
499 static void MountGlobalDrives()
503 hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
505 if ( hThreadMountGlobalDrives ) {
506 DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
507 if (rc == WAIT_TIMEOUT) {
508 afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
509 } else if (rc == WAIT_OBJECT_0) {
510 afsi_log("GlobalAutoMap thread completed");
511 CloseHandle( hThreadMountGlobalDrives );
512 hThreadMountGlobalDrives = NULL;
517 static void DismountGlobalDrives()
519 char szAfsPath[_MAX_PATH];
520 char szDriveToMapTo[5];
522 DWORD dwSubMountSize;
523 char szSubMount[256];
530 if ( hThreadMountGlobalDrives ) {
531 DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
533 if (rc == WAIT_TIMEOUT) {
534 afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
536 else if (rc == WAIT_OBJECT_0) {
537 afsi_log("GlobalAutoMap thread completed");
538 CloseHandle( hThreadMountGlobalDrives );
539 hThreadMountGlobalDrives = NULL;
543 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
545 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
546 if (dwResult != ERROR_SUCCESS)
549 while (dwIndex < MAX_DRIVES) {
550 dwDriveSize = sizeof(szDriveToMapTo);
551 dwSubMountSize = sizeof(szSubMount);
552 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
553 if (dwResult != ERROR_MORE_DATA) {
554 if (dwResult != ERROR_SUCCESS) {
555 if (dwResult != ERROR_NO_MORE_ITEMS)
556 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
561 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
563 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
564 dwResult = WNetCancelConnection(szAfsPath, TRUE);
566 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
573 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
575 DWORD dwVersionHandle;
576 LPVOID pVersionInfo = 0;
578 LPDWORD pLangInfo = 0;
579 LPTSTR szVersion = 0;
581 TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
582 DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
585 afsi_log("GetFileVersionInfoSize failed");
586 return GetLastError();
589 pVersionInfo = malloc(size);
591 afsi_log("out of memory 1");
592 return ERROR_NOT_ENOUGH_MEMORY;
595 GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
596 if (retval = GetLastError())
598 afsi_log("GetFileVersionInfo failed: %d", retval);
602 VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
603 (LPVOID*)&pLangInfo, &len);
604 if (retval = GetLastError())
606 afsi_log("VerQueryValue 1 failed: %d", retval);
611 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
612 LOWORD(*pLangInfo), HIWORD(*pLangInfo));
614 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
615 if (retval = GetLastError())
617 /* try again with language 409 since the old binaries were tagged wrong */
619 TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
622 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
623 if (retval = GetLastError()) {
624 afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
628 snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
629 szOutput[dwOutput - 1] = 0;
638 static HINSTANCE hCrypt32;
639 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags,
640 void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
641 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
642 DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
643 DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
644 DWORD* pdwFormatType, HCERTSTORE* phCertStore,
645 HCRYPTMSG* phMsg, const void** ppvContext);
646 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
647 void* pvData, DWORD* pcbData);
648 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
649 DWORD dwFindFlags, DWORD dwFindType,
650 const void* pvFindPara,
651 PCCERT_CONTEXT pPrevCertContext);
652 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
653 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
654 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
655 PCERT_INFO pCertId2);
656 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
658 void LoadCrypt32(void)
660 hCrypt32 = LoadLibrary("crypt32");
664 (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
665 (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
666 (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
667 (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
668 (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
669 (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
670 (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
671 (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
673 if ( !pCertGetNameString ||
674 !pCryptQueryObject ||
675 !pCryptMsgGetParam ||
676 !pCertFindCertificateInStore ||
679 !pCertCompareCertificate ||
680 !pCertFreeCertificateContext)
682 FreeLibrary(hCrypt32);
687 void UnloadCrypt32(void)
689 FreeLibrary(hCrypt32);
692 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
694 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
696 wchar_t wfilename[260];
702 HCERTSTORE hStore = NULL;
703 HCRYPTMSG hMsg = NULL;
704 PCMSG_SIGNER_INFO pSignerInfo = NULL;
705 PCCERT_CONTEXT pCertContext = NULL;
708 if ( hCrypt32 == NULL )
711 ZeroMemory(&CertInfo, sizeof(CertInfo));
712 mbstowcs(wfilename, filename, 260);
714 fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
716 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
717 CERT_QUERY_FORMAT_FLAG_BINARY,
727 afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
733 fResult = pCryptMsgGetParam(hMsg,
734 CMSG_SIGNER_INFO_PARAM,
740 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
746 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
748 fResult = pCryptMsgGetParam(hMsg,
749 CMSG_SIGNER_INFO_PARAM,
755 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
761 CertInfo.Issuer = pSignerInfo->Issuer;
762 CertInfo.SerialNumber = pSignerInfo->SerialNumber;
764 pCertContext = pCertFindCertificateInStore(hStore,
767 CERT_FIND_SUBJECT_CERT,
772 afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
780 LocalFree(pSignerInfo);
783 CertFreeCertificateContext(pCertContext);*/
786 pCertCloseStore(hStore,0);
789 pCryptMsgClose(hMsg);
794 BOOL VerifyTrust(CHAR * filename)
796 WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
797 WIN_TRUST_SUBJECT_FILE fSubjectFile;
798 GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
799 GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
800 wchar_t wfilename[260];
802 BOOL success = FALSE;
804 LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
807 if (filename == NULL )
810 hWinTrust = LoadLibrary("wintrust");
814 if (((FARPROC) pWinVerifyTrust =
815 GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
817 FreeLibrary(hWinTrust);
821 mbstowcs(wfilename, filename, 260);
823 fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
825 fSubjectFile.lpPath = wfilename;
826 fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
827 FALSE, GetCurrentProcessId());
828 fContextWSubject.SubjectType = &subject;
829 fContextWSubject.Subject = &fSubjectFile;
831 ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
833 if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
834 CloseHandle( fSubjectFile.hFile );
835 if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
836 CloseHandle( fContextWSubject.hClientToken );
838 if (ret == ERROR_SUCCESS) {
841 DWORD gle = GetLastError();
843 case TRUST_E_PROVIDER_UNKNOWN:
844 afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
846 case TRUST_E_NOSIGNATURE:
847 afsi_log("VerifyTrust failed: Unsigned executable");
849 case TRUST_E_EXPLICIT_DISTRUST:
850 afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
852 case TRUST_E_SUBJECT_NOT_TRUSTED:
853 afsi_log("VerifyTrust failed: File is not trusted");
855 case TRUST_E_BAD_DIGEST:
856 afsi_log("VerifyTrust failed: Executable has been modified");
858 case CRYPT_E_SECURITY_SETTINGS:
859 afsi_log("VerifyTrust failed: local security options prevent verification");
862 afsi_log("VerifyTrust failed: 0x%X", GetLastError());
866 FreeLibrary(hWinTrust);
870 void LogCertCtx(PCCERT_CONTEXT pCtx) {
872 LPTSTR szName = NULL;
874 if ( hCrypt32 == NULL )
877 // Get Issuer name size.
878 if (!(dwData = pCertGetNameString(pCtx,
879 CERT_NAME_SIMPLE_DISPLAY_TYPE,
880 CERT_NAME_ISSUER_FLAG,
884 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
888 // Allocate memory for Issuer name.
889 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
892 if (!(pCertGetNameString(pCtx,
893 CERT_NAME_SIMPLE_DISPLAY_TYPE,
894 CERT_NAME_ISSUER_FLAG,
898 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
902 // print Issuer name.
903 afsi_log("Issuer Name: %s", szName);
907 // Get Subject name size.
908 if (!(dwData = pCertGetNameString(pCtx,
909 CERT_NAME_SIMPLE_DISPLAY_TYPE,
914 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
918 // Allocate memory for subject name.
919 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
922 if (!(pCertGetNameString(pCtx,
923 CERT_NAME_SIMPLE_DISPLAY_TYPE,
928 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
932 // Print Subject Name.
933 afsi_log("Subject Name: %s", szName);
941 BOOL AFSModulesVerify(void)
944 CHAR afsdVersion[128];
945 CHAR modVersion[128];
946 CHAR checkName[1024];
947 BOOL trustVerified = FALSE;
953 PCCERT_CONTEXT pCtxService = NULL;
955 DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
956 BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
957 DWORD dummyLen, code;
958 DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
959 DWORD verifyServiceSig = TRUE;
962 hPSAPI = LoadLibrary("psapi");
964 if ( hPSAPI == NULL )
967 if (!GetModuleFileName(NULL, filename, sizeof(filename)))
970 if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
973 afsi_log("%s version %s", filename, afsdVersion);
975 if (((FARPROC) pGetModuleFileNameExA =
976 GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
977 ((FARPROC) pEnumProcessModules =
978 GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
985 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
986 AFSREG_CLT_SVC_PARAM_SUBKEY,
987 0, KEY_QUERY_VALUE, &parmKey);
988 if (code == ERROR_SUCCESS) {
989 dummyLen = sizeof(cacheSize);
990 code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
991 (BYTE *) &cacheSize, &dummyLen);
992 RegCloseKey (parmKey);
995 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
996 0, KEY_QUERY_VALUE, &parmKey);
997 if (code == ERROR_SUCCESS) {
998 dummyLen = sizeof(verifyServiceSig);
999 code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
1000 (BYTE *) &verifyServiceSig, &dummyLen);
1001 RegCloseKey (parmKey);
1004 if (verifyServiceSig
1006 && cacheSize < 716800
1009 trustVerified = VerifyTrust(filename);
1011 afsi_log("Signature Verification disabled");
1014 if (trustVerified) {
1017 // get a certificate context for the signer of afsd_service.
1018 pCtxService = GetCertCtx(filename);
1020 LogCertCtx(pCtxService);
1023 // Get a list of all the modules in this process.
1024 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1025 FALSE, GetCurrentProcessId());
1027 if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1029 afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1031 for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1033 char szModName[2048];
1035 // Get the full path to the module's file.
1036 if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1038 lstrcpy(checkName, szModName);
1041 if ( strstr(checkName, "afspthread.dll") ||
1042 strstr(checkName, "afsauthent.dll") ||
1043 strstr(checkName, "afsrpc.dll") ||
1044 strstr(checkName, "libafsconf.dll") ||
1045 strstr(checkName, "libosi.dll") )
1047 if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1052 afsi_log("%s version %s", szModName, modVersion);
1053 if (strcmp(afsdVersion,modVersion)) {
1054 afsi_log("Version mismatch: %s", szModName);
1057 if ( trustVerified ) {
1058 if ( !VerifyTrust(szModName) ) {
1059 afsi_log("Signature Verification failed: %s", szModName);
1062 else if (pCtxService) {
1063 PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1065 if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1066 pCtxService->pCertInfo,
1068 afsi_log("Certificate mismatch: %s", szModName);
1076 pCertFreeCertificateContext(pCtx);
1085 pCertFreeCertificateContext(pCtxService);
1089 FreeLibrary(hPSAPI);
1091 CloseHandle(hProcess);
1096 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1099 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1100 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
1102 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1103 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
1106 afsd_Main(DWORD argc, LPTSTR *argv)
1118 void afsd_DbgBreakAllocInit();
1120 afsd_DbgBreakAllocInit();
1121 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
1122 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1125 afsd_SetUnhandledExceptionFilter();
1127 osi_InitPanic(afsd_notifier);
1128 osi_InitTraceOption();
1130 hKernel32 = LoadLibrary("kernel32.dll");
1131 if (hKernel32 == NULL)
1133 afsi_log("Fatal: cannot load kernel32.dll");
1136 pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
1142 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1143 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1144 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1147 hAdvApi32 = LoadLibrary("advapi32.dll");
1148 if (hAdvApi32 == NULL)
1150 afsi_log("Fatal: cannot load advapi32.dll");
1154 if (bRunningAsService) {
1155 pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
1156 if (pRegisterServiceCtrlHandlerEx)
1158 afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
1159 StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
1163 StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
1166 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1167 ServiceStatus.dwServiceSpecificExitCode = 0;
1168 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1169 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1170 ServiceStatus.dwCheckPoint = 1;
1171 ServiceStatus.dwWaitHint = 120000;
1172 /* accept Power Events */
1173 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1174 SetServiceStatus(StatusHandle, &ServiceStatus);
1178 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
1180 #ifdef REGISTER_POWER_NOTIFICATIONS
1187 /* see if we should handle power notifications */
1188 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1189 0, KEY_QUERY_VALUE, &hkParm);
1190 if (code == ERROR_SUCCESS) {
1191 dummyLen = sizeof(bpower);
1192 code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
1193 (BYTE *) &bpower, &dummyLen);
1195 if(code != ERROR_SUCCESS)
1198 RegCloseKey(hkParm);
1200 /* create thread used to flush cache */
1202 PowerNotificationThreadCreate();
1203 powerEventsRegistered = 1;
1208 /* Verify the versions of the DLLs which were loaded */
1209 if (!AFSModulesVerify()) {
1210 if (bRunningAsService) {
1211 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1212 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1213 ServiceStatus.dwCheckPoint = 0;
1214 ServiceStatus.dwWaitHint = 0;
1215 ServiceStatus.dwControlsAccepted = 0;
1216 SetServiceStatus(StatusHandle, &ServiceStatus);
1218 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1220 /* exit if initialization failed */
1224 /* allow an exit to be called prior to any initialization */
1225 hHookDll = cm_LoadAfsdHookLib();
1229 AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1232 hookRc = initHook();
1234 FreeLibrary(hHookDll);
1237 if (hookRc == FALSE)
1239 if (bRunningAsService) {
1240 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1241 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1242 ServiceStatus.dwCheckPoint = 0;
1243 ServiceStatus.dwWaitHint = 0;
1244 ServiceStatus.dwControlsAccepted = 0;
1245 SetServiceStatus(StatusHandle, &ServiceStatus);
1247 /* exit if initialization failed */
1252 /* allow another 120 seconds to start */
1253 if (bRunningAsService) {
1254 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1255 ServiceStatus.dwServiceSpecificExitCode = 0;
1256 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1257 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1258 ServiceStatus.dwCheckPoint = 2;
1259 ServiceStatus.dwWaitHint = 120000;
1260 /* accept Power Events */
1261 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1262 SetServiceStatus(StatusHandle, &ServiceStatus);
1267 /* Perform Volume Status Notification Initialization */
1268 cm_VolStatus_Initialization();
1271 MainThreadId = GetCurrentThreadId();
1272 jmpret = setjmp(notifier_jmp);
1277 code = afsd_InitCM(&reason);
1279 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1280 osi_panic(reason, __FILE__, __LINE__);
1284 if (bRunningAsService) {
1285 ServiceStatus.dwCheckPoint = 3;
1286 ServiceStatus.dwWaitHint = 30000;
1287 SetServiceStatus(StatusHandle, &ServiceStatus);
1290 /* allow an exit to be called post rx initialization */
1291 hHookDll = cm_LoadAfsdHookLib();
1295 AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1298 hookRc = rxStartedHook();
1300 FreeLibrary(hHookDll);
1303 if (hookRc == FALSE)
1305 if (bRunningAsService) {
1306 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1307 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1308 ServiceStatus.dwCheckPoint = 0;
1309 ServiceStatus.dwWaitHint = 0;
1310 ServiceStatus.dwControlsAccepted = 0;
1311 SetServiceStatus(StatusHandle, &ServiceStatus);
1313 /* exit if initialization failed */
1319 if (bRunningAsService) {
1320 ServiceStatus.dwCheckPoint = 4;
1321 ServiceStatus.dwWaitHint = 15000;
1322 SetServiceStatus(StatusHandle, &ServiceStatus);
1326 /* Notify any volume status handlers that the cache manager has started */
1327 cm_VolStatus_Service_Started();
1329 code = afsd_InitSMB(&reason, MessageBox);
1331 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1332 osi_panic(reason, __FILE__, __LINE__);
1335 /* allow an exit to be called post smb initialization */
1336 hHookDll = cm_LoadAfsdHookLib();
1340 AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1343 hookRc = smbStartedHook();
1345 FreeLibrary(hHookDll);
1348 if (hookRc == FALSE)
1350 if (bRunningAsService) {
1351 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1352 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1353 ServiceStatus.dwCheckPoint = 0;
1354 ServiceStatus.dwWaitHint = 0;
1355 ServiceStatus.dwControlsAccepted = 0;
1356 SetServiceStatus(StatusHandle, &ServiceStatus);
1358 /* exit if initialization failed */
1363 MountGlobalDrives();
1365 code = afsd_InitDaemons(&reason);
1367 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1368 osi_panic(reason, __FILE__, __LINE__);
1372 if (bRunningAsService) {
1373 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1374 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1375 ServiceStatus.dwCheckPoint = 5;
1376 ServiceStatus.dwWaitHint = 0;
1378 /* accept Power events */
1379 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1380 SetServiceStatus(StatusHandle, &ServiceStatus);
1384 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1387 /* allow an exit to be called when started */
1388 hHookDll = cm_LoadAfsdHookLib();
1392 AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1395 hookRc = startedHook();
1397 FreeLibrary(hHookDll);
1400 if (hookRc == FALSE)
1402 if (bRunningAsService) {
1403 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1404 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1405 ServiceStatus.dwCheckPoint = 0;
1406 ServiceStatus.dwWaitHint = 0;
1407 ServiceStatus.dwControlsAccepted = 0;
1408 SetServiceStatus(StatusHandle, &ServiceStatus);
1410 /* exit if initialization failed */
1415 WaitForSingleObject(WaitToTerminate, INFINITE);
1417 if (bRunningAsService) {
1418 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1419 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1420 ServiceStatus.dwCheckPoint = 6;
1421 ServiceStatus.dwWaitHint = 120000;
1422 ServiceStatus.dwControlsAccepted = 0;
1423 SetServiceStatus(StatusHandle, &ServiceStatus);
1425 afsi_log("Received Termination Signal, Stopping Service");
1428 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP);
1430 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
1432 /* allow an exit to be called prior to stopping the service */
1433 hHookDll = cm_LoadAfsdHookLib();
1437 AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
1440 hookRc = stoppingHook();
1442 FreeLibrary(hHookDll);
1447 #ifdef AFS_FREELANCE_CLIENT
1448 cm_FreelanceShutdown();
1449 afsi_log("Freelance Shutdown complete");
1452 DismountGlobalDrives();
1453 afsi_log("Global Drives dismounted");
1456 afsi_log("smb shutdown complete");
1460 cm_ReleaseAllLocks();
1462 cm_DaemonShutdown();
1463 afsi_log("Daemon shutdown complete");
1466 afsi_log("Buffer shutdown complete");
1470 cm_ShutdownMappedMemory();
1473 afsi_log("rx finalization complete");
1475 #ifdef REGISTER_POWER_NOTIFICATIONS
1476 /* terminate thread used to flush cache */
1477 if (powerEventsRegistered)
1478 PowerNotificationThreadExit();
1483 cm_BPlusDumpStats();
1486 /* Notify any Volume Status Handlers that we are stopped */
1487 cm_VolStatus_Service_Stopped();
1489 /* Cleanup any Volume Status Notification Handler */
1490 cm_VolStatus_Finalize();
1492 /* allow an exit to be called after stopping the service */
1493 hHookDll = cm_LoadAfsdHookLib();
1497 AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1500 hookRc = stoppedHook();
1502 FreeLibrary(hHookDll);
1506 /* Remove the ExceptionFilter */
1507 SetUnhandledExceptionFilter(NULL);
1509 if (bRunningAsService) {
1510 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1511 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1512 ServiceStatus.dwCheckPoint = 7;
1513 ServiceStatus.dwWaitHint = 0;
1514 ServiceStatus.dwControlsAccepted = 0;
1515 SetServiceStatus(StatusHandle, &ServiceStatus);
1519 DWORD __stdcall afsdMain_thread(void* notUsed)
1521 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1522 afsd_Main(1, (LPTSTR*)argv);
1528 fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1532 main(int argc, char * argv[])
1534 static SERVICE_TABLE_ENTRY dispatchTable[] = {
1535 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1540 for (i = 1; i < argc; i++) {
1541 if (!stricmp(argv[i],"--validate-cache")) {
1542 if (++i != argc - 1) {
1547 return cm_ValidateMappedMemory(argv[i]);
1554 if (!StartServiceCtrlDispatcher(dispatchTable))
1556 LONG status = GetLastError();
1557 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1561 bRunningAsService = FALSE;
1563 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1565 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1567 SetEvent(WaitToTerminate);
1571 if ( hAFSDMainThread ) {
1572 WaitForSingleObject( hAFSDMainThread, INFINITE );
1573 CloseHandle( hAFSDMainThread );