11 #include "afsd_init.h"
12 #include "lanahelper.h"
16 #include <WINNT\afsreg.h>
28 //#define REGISTER_POWER_NOTIFICATIONS 1
29 #include "afsd_flushvol.h"
31 extern void afsi_log(char *pattern, ...);
33 static SERVICE_STATUS ServiceStatus;
34 static SERVICE_STATUS_HANDLE StatusHandle;
36 HANDLE hAFSDMainThread = NULL;
38 HANDLE hAFSDWorkerThread[WORKER_THREADS];
41 HANDLE WaitToTerminate;
43 static int GlobalStatus;
46 unsigned int MainThreadId;
50 extern int traceOnPanic;
51 extern HANDLE afsi_file;
53 static int powerEventsRegistered = 0;
54 extern int powerStateSuspended = 0;
57 * Notifier function for use by osi_panic
59 static void afsd_notifier(char *msgp, char *filep, long line)
65 msgp = "unspecified assert";
68 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION,
71 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG, msgp);
75 osi_LogEnable(afsd_logp);
77 afsd_ForceTrace(TRUE);
80 afsi_log("--- begin dump ---");
81 cm_MemDumpDirStats(afsi_file, "a", 0);
82 cm_MemDumpBPlusStats(afsi_file, "a", 0);
83 cm_DumpCells(afsi_file, "a", 0);
84 cm_DumpVolumes(afsi_file, "a", 0);
85 cm_DumpSCache(afsi_file, "a", 0);
87 cm_dnlcDump(afsi_file, "a");
89 cm_DumpBufHashTable(afsi_file, "a", 0);
90 smb_DumpVCP(afsi_file, "a", 0);
91 afsi_log("--- end dump ---");
94 if (IsDebuggerPresent())
98 SetEvent(WaitToTerminate);
100 WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
101 for (i = 0; i < WORKER_THREADS; i++)
102 CloseHandle(hAFSDWorkerThread[i]);
106 if (GetCurrentThreadId() == MainThreadId)
107 longjmp(notifier_jmp, 1);
110 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
111 ServiceStatus.dwWin32ExitCode = NO_ERROR;
112 ServiceStatus.dwCheckPoint = 0;
113 ServiceStatus.dwWaitHint = 0;
114 ServiceStatus.dwControlsAccepted = 0;
115 SetServiceStatus(StatusHandle, &ServiceStatus);
121 * For use miscellaneously in smb.c; need to do better
123 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
129 afsd_ServiceFlushVolume(DWORD dwlpEventData)
131 DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
134 ** If UI bit is not set, user interaction is not possible
135 ** BUT, since we are a NON-interactive service, and therefore
136 ** have NO user I/O, it doesn't much matter.
137 ** This benign code left here as example of how to find this out
139 BOOL bUI = (dwlpEventData & 1);
142 if ( PowerNotificationThreadNotify() )
148 /* flush was unsuccessful, or timeout - deny shutdown */
149 dwRet = ERROR_NETWORK_BUSY;
152 /* to deny hibernate, simply return
153 // any value besides NO_ERROR.
155 // dwRet = ERROR_NETWORK_BUSY;
162 /* service control handler used in nt4 only for backward compat. */
164 afsd_ServiceControlHandler(DWORD ctrlCode)
167 DWORD dummyLen, doTrace;
171 case SERVICE_CONTROL_SHUTDOWN:
172 case SERVICE_CONTROL_STOP:
173 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
174 ServiceStatus.dwWin32ExitCode = NO_ERROR;
175 ServiceStatus.dwCheckPoint = 1;
176 ServiceStatus.dwWaitHint = 30000;
177 ServiceStatus.dwControlsAccepted = 0;
178 SetServiceStatus(StatusHandle, &ServiceStatus);
180 if (ctrlCode == SERVICE_CONTROL_STOP)
181 afsi_log("SERVICE_CONTROL_STOP");
183 afsi_log("SERVICE_CONTROL_SHUTDOWN");
185 /* Write all dirty buffers back to server */
186 if ( !lana_OnlyLoopback() )
189 /* Force trace if requested */
190 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
191 AFSREG_CLT_SVC_PARAM_SUBKEY,
192 0, KEY_QUERY_VALUE, &parmKey);
193 if (code != ERROR_SUCCESS)
196 dummyLen = sizeof(doTrace);
197 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
199 (BYTE *) &doTrace, &dummyLen);
200 RegCloseKey (parmKey);
201 if (code != ERROR_SUCCESS)
204 afsd_ForceTrace(FALSE);
205 buf_ForceTrace(FALSE);
209 SetEvent(WaitToTerminate);
212 case SERVICE_CONTROL_INTERROGATE:
213 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
214 ServiceStatus.dwWin32ExitCode = NO_ERROR;
215 ServiceStatus.dwCheckPoint = 0;
216 ServiceStatus.dwWaitHint = 0;
217 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
218 SetServiceStatus(StatusHandle, &ServiceStatus);
220 /* XXX handle system shutdown */
221 /* XXX handle pause & continue */
227 ** Extended ServiceControlHandler that provides Event types
228 ** for monitoring Power events, for example.
231 afsd_ServiceControlHandlerEx(
239 DWORD dummyLen, doTrace;
241 DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
242 OSVERSIONINFO osVersion;
244 /* Get the version of Windows */
245 memset(&osVersion, 0x00, sizeof(osVersion));
246 osVersion.dwOSVersionInfoSize = sizeof(osVersion);
247 GetVersionEx(&osVersion);
251 case SERVICE_CONTROL_SHUTDOWN:
252 case SERVICE_CONTROL_STOP:
253 if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
254 afsi_log("SERVICE_CONTROL_SHUTDOWN");
256 afsi_log("SERVICE_CONTROL_STOP");
258 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
259 ServiceStatus.dwWin32ExitCode = NO_ERROR;
260 ServiceStatus.dwCheckPoint = 1;
261 ServiceStatus.dwWaitHint = 30000;
262 ServiceStatus.dwControlsAccepted = 0;
263 SetServiceStatus(StatusHandle, &ServiceStatus);
265 /* Write all dirty buffers back to server */
266 if ( !lana_OnlyLoopback() )
269 /* Force trace if requested */
270 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
271 AFSREG_CLT_SVC_PARAM_SUBKEY,
272 0, KEY_QUERY_VALUE, &parmKey);
273 if (code != ERROR_SUCCESS)
276 dummyLen = sizeof(doTrace);
277 code = RegQueryValueEx(parmKey, "TraceOnShutdown",
279 (BYTE *) &doTrace, &dummyLen);
280 RegCloseKey (parmKey);
281 if (code != ERROR_SUCCESS)
284 afsd_ForceTrace(FALSE);
285 buf_ForceTrace(FALSE);
289 SetEvent(WaitToTerminate);
293 case SERVICE_CONTROL_INTERROGATE:
294 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
295 ServiceStatus.dwWin32ExitCode = NO_ERROR;
296 ServiceStatus.dwCheckPoint = 0;
297 ServiceStatus.dwWaitHint = 0;
298 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
299 SetServiceStatus(StatusHandle, &ServiceStatus);
300 afsi_log("SERVICE_CONTROL_INTERROGATE");
304 /* XXX handle system shutdown */
305 /* XXX handle pause & continue */
306 case SERVICE_CONTROL_POWEREVENT:
309 afsi_log("SERVICE_CONTROL_POWEREVENT");
312 ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
313 ** Return NO_ERROR == return TRUE for that message, i.e. accept request
314 ** Return any error code to deny request,
315 ** i.e. as if returning BROADCAST_QUERY_DENY
317 if (powerEventsRegistered) {
318 switch((int) dwEventType)
320 case PBT_APMQUERYSUSPEND:
321 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND");
322 /* Write all dirty buffers back to server */
323 if ( !lana_OnlyLoopback() ) {
327 afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete");
330 case PBT_APMQUERYSTANDBY:
331 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY");
332 /* Write all dirty buffers back to server */
333 if ( !lana_OnlyLoopback() ) {
337 afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete");
341 /* allow remaining case PBT_WhatEver */
343 afsi_log("SERVICE_CONTROL_APMSUSPEND");
344 powerStateSuspended = 1;
345 if (osVersion.dwMajorVersion >= 6) {
347 smb_StopListeners(0);
352 afsi_log("SERVICE_CONTROL_APMSTANDBY");
353 powerStateSuspended = 1;
354 if (osVersion.dwMajorVersion >= 6) {
356 smb_StopListeners(0);
360 case PBT_APMRESUMECRITICAL:
361 afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL");
362 if (osVersion.dwMajorVersion >= 6)
363 smb_RestartListeners(0);
366 case PBT_APMRESUMESUSPEND:
367 /* User logged in after suspend */
368 afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND");
371 case PBT_APMRESUMESTANDBY:
372 /* User logged in after standby */
373 afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY");
376 case PBT_APMBATTERYLOW:
377 afsi_log("SERVICE_CONTROL_APMBATTERYLOW");
380 case PBT_APMPOWERSTATUSCHANGE:
382 afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
386 case PBT_APMOEMEVENT:
388 afsi_log("SERVICE_CONTROL_APMOEMEVENT");
392 case PBT_APMRESUMEAUTOMATIC:
393 /* This is the message delivered once all devices are up */
394 afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC");
395 powerStateSuspended = 0;
396 if (osVersion.dwMajorVersion >= 6) {
397 smb_SetLanAdapterChangeDetected();
402 afsi_log("SERVICE_CONTROL_unknown");
408 case SERVICE_CONTROL_CUSTOM_DUMP:
410 afsi_log("SERVICE_CONTROL_CUSTOM_DUMP");
411 GenerateMiniDump(NULL);
415 } /* end switch(ctrlCode) */
419 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
421 * Mount a drive into AFS if there global mapping
423 /* DEE Could check first if we are run as SYSTEM */
424 #define MAX_RETRIES 10
425 #define MAX_DRIVES 23
426 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
429 char szAfsPath[_MAX_PATH];
431 char szDriveToMapTo[5];
435 DWORD dwIndex = 0, dwRetry = 0;
437 DWORD dwSubMountSize;
438 char szSubMount[256];
441 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
443 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
444 if (dwResult != ERROR_SUCCESS)
447 while (dwIndex < MAX_DRIVES) {
448 dwDriveSize = sizeof(szDriveToMapTo);
449 dwSubMountSize = sizeof(szSubMount);
450 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
451 if (dwResult != ERROR_MORE_DATA) {
452 if (dwResult != ERROR_SUCCESS) {
453 if (dwResult != ERROR_NO_MORE_ITEMS)
454 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);
487 /* FIXFIX: implement */
488 afsi_log("GlobalAutoMap of %s to %s not implemented", szDriveToMapTo, szSubMount);
496 static HANDLE hThreadMountGlobalDrives = NULL;
498 static void MountGlobalDrives()
502 hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
504 if ( hThreadMountGlobalDrives ) {
505 DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
506 if (rc == WAIT_TIMEOUT) {
507 afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
508 } else if (rc == WAIT_OBJECT_0) {
509 afsi_log("GlobalAutoMap thread completed");
510 CloseHandle( hThreadMountGlobalDrives );
511 hThreadMountGlobalDrives = NULL;
516 static void DismountGlobalDrives()
519 char szAfsPath[_MAX_PATH];
520 char szDriveToMapTo[5];
522 DWORD dwSubMountSize;
523 char szSubMount[256];
531 if ( hThreadMountGlobalDrives ) {
532 DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
534 if (rc == WAIT_TIMEOUT) {
535 afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
537 else if (rc == WAIT_OBJECT_0) {
538 afsi_log("GlobalAutoMap thread completed");
539 CloseHandle( hThreadMountGlobalDrives );
540 hThreadMountGlobalDrives = NULL;
544 sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
546 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
547 if (dwResult != ERROR_SUCCESS)
551 /* FIXFIX: implement */
553 while (dwIndex < MAX_DRIVES) {
554 dwDriveSize = sizeof(szDriveToMapTo);
555 dwSubMountSize = sizeof(szSubMount);
556 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
557 if (dwResult != ERROR_MORE_DATA) {
558 if (dwResult != ERROR_SUCCESS) {
559 if (dwResult != ERROR_NO_MORE_ITEMS)
560 afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
565 sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
567 dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
568 dwResult = WNetCancelConnection(szAfsPath, TRUE);
570 afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
578 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
580 DWORD dwVersionHandle;
581 LPVOID pVersionInfo = 0;
583 LPDWORD pLangInfo = 0;
584 LPTSTR szVersion = 0;
586 TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
587 DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
590 afsi_log("GetFileVersionInfoSize failed");
591 return GetLastError();
594 pVersionInfo = malloc(size);
596 afsi_log("out of memory 1");
597 return ERROR_NOT_ENOUGH_MEMORY;
600 GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
601 if (retval = GetLastError())
603 afsi_log("GetFileVersionInfo failed: %d", retval);
607 VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
608 (LPVOID*)&pLangInfo, &len);
609 if (retval = GetLastError())
611 afsi_log("VerQueryValue 1 failed: %d", retval);
616 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
617 LOWORD(*pLangInfo), HIWORD(*pLangInfo));
619 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
620 if (retval = GetLastError())
622 /* try again with language 409 since the old binaries were tagged wrong */
624 TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
627 VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
628 if (retval = GetLastError()) {
629 afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
633 snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
634 szOutput[dwOutput - 1] = 0;
643 static HINSTANCE hCrypt32;
644 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags,
645 void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
646 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
647 DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
648 DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
649 DWORD* pdwFormatType, HCERTSTORE* phCertStore,
650 HCRYPTMSG* phMsg, const void** ppvContext);
651 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
652 void* pvData, DWORD* pcbData);
653 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
654 DWORD dwFindFlags, DWORD dwFindType,
655 const void* pvFindPara,
656 PCCERT_CONTEXT pPrevCertContext);
657 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
658 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
659 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
660 PCERT_INFO pCertId2);
661 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
663 void LoadCrypt32(void)
665 hCrypt32 = LoadLibrary("crypt32");
669 (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
670 (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
671 (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
672 (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
673 (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
674 (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
675 (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
676 (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
678 if ( !pCertGetNameString ||
679 !pCryptQueryObject ||
680 !pCryptMsgGetParam ||
681 !pCertFindCertificateInStore ||
684 !pCertCompareCertificate ||
685 !pCertFreeCertificateContext)
687 FreeLibrary(hCrypt32);
692 void UnloadCrypt32(void)
694 FreeLibrary(hCrypt32);
697 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
699 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
701 wchar_t wfilename[260];
707 HCERTSTORE hStore = NULL;
708 HCRYPTMSG hMsg = NULL;
709 PCMSG_SIGNER_INFO pSignerInfo = NULL;
710 PCCERT_CONTEXT pCertContext = NULL;
713 if ( hCrypt32 == NULL )
716 ZeroMemory(&CertInfo, sizeof(CertInfo));
717 mbstowcs(wfilename, filename, 260);
719 fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
721 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
722 CERT_QUERY_FORMAT_FLAG_BINARY,
732 afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
738 fResult = pCryptMsgGetParam(hMsg,
739 CMSG_SIGNER_INFO_PARAM,
745 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
751 pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
753 fResult = pCryptMsgGetParam(hMsg,
754 CMSG_SIGNER_INFO_PARAM,
760 afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
766 CertInfo.Issuer = pSignerInfo->Issuer;
767 CertInfo.SerialNumber = pSignerInfo->SerialNumber;
769 pCertContext = pCertFindCertificateInStore(hStore,
772 CERT_FIND_SUBJECT_CERT,
777 afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
785 LocalFree(pSignerInfo);
788 CertFreeCertificateContext(pCertContext);*/
791 pCertCloseStore(hStore,0);
794 pCryptMsgClose(hMsg);
799 BOOL VerifyTrust(CHAR * filename)
801 WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
802 WIN_TRUST_SUBJECT_FILE fSubjectFile;
803 GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
804 GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
805 wchar_t wfilename[260];
807 BOOL success = FALSE;
809 LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
812 if (filename == NULL )
815 hWinTrust = LoadLibrary("wintrust");
819 if (((FARPROC) pWinVerifyTrust =
820 GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
822 FreeLibrary(hWinTrust);
826 mbstowcs(wfilename, filename, 260);
828 fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
830 fSubjectFile.lpPath = wfilename;
831 fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
832 FALSE, GetCurrentProcessId());
833 fContextWSubject.SubjectType = &subject;
834 fContextWSubject.Subject = &fSubjectFile;
836 ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
838 if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
839 CloseHandle( fSubjectFile.hFile );
840 if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
841 CloseHandle( fContextWSubject.hClientToken );
843 if (ret == ERROR_SUCCESS) {
846 DWORD gle = GetLastError();
848 case TRUST_E_PROVIDER_UNKNOWN:
849 afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
851 case TRUST_E_NOSIGNATURE:
852 afsi_log("VerifyTrust failed: Unsigned executable");
854 case TRUST_E_EXPLICIT_DISTRUST:
855 afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
857 case TRUST_E_SUBJECT_NOT_TRUSTED:
858 afsi_log("VerifyTrust failed: File is not trusted");
860 case TRUST_E_BAD_DIGEST:
861 afsi_log("VerifyTrust failed: Executable has been modified");
863 case CRYPT_E_SECURITY_SETTINGS:
864 afsi_log("VerifyTrust failed: local security options prevent verification");
867 afsi_log("VerifyTrust failed: 0x%X", GetLastError());
871 FreeLibrary(hWinTrust);
875 void LogCertCtx(PCCERT_CONTEXT pCtx) {
877 LPTSTR szName = NULL;
879 if ( hCrypt32 == NULL )
882 // Get Issuer name size.
883 if (!(dwData = pCertGetNameString(pCtx,
884 CERT_NAME_SIMPLE_DISPLAY_TYPE,
885 CERT_NAME_ISSUER_FLAG,
889 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
893 // Allocate memory for Issuer name.
894 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
897 if (!(pCertGetNameString(pCtx,
898 CERT_NAME_SIMPLE_DISPLAY_TYPE,
899 CERT_NAME_ISSUER_FLAG,
903 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
907 // print Issuer name.
908 afsi_log("Issuer Name: %s", szName);
912 // Get Subject name size.
913 if (!(dwData = pCertGetNameString(pCtx,
914 CERT_NAME_SIMPLE_DISPLAY_TYPE,
919 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
923 // Allocate memory for subject name.
924 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
927 if (!(pCertGetNameString(pCtx,
928 CERT_NAME_SIMPLE_DISPLAY_TYPE,
933 afsi_log("CertGetNameString failed: 0x%x", GetLastError());
937 // Print Subject Name.
938 afsi_log("Subject Name: %s", szName);
946 BOOL AFSModulesVerify(void)
949 CHAR afsdVersion[128];
950 CHAR modVersion[128];
951 CHAR checkName[1024];
952 BOOL trustVerified = FALSE;
958 PCCERT_CONTEXT pCtxService = NULL;
960 DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
961 BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
962 DWORD dummyLen, code;
963 DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
964 DWORD verifyServiceSig = TRUE;
967 hPSAPI = LoadLibrary("psapi");
969 if ( hPSAPI == NULL )
972 if (!GetModuleFileName(NULL, filename, sizeof(filename)))
975 if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
978 afsi_log("%s version %s", filename, afsdVersion);
980 if (((FARPROC) pGetModuleFileNameExA =
981 GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
982 ((FARPROC) pEnumProcessModules =
983 GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
990 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
991 AFSREG_CLT_SVC_PARAM_SUBKEY,
992 0, KEY_QUERY_VALUE, &parmKey);
993 if (code == ERROR_SUCCESS) {
994 dummyLen = sizeof(cacheSize);
995 code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
996 (BYTE *) &cacheSize, &dummyLen);
997 RegCloseKey (parmKey);
1000 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
1001 0, KEY_QUERY_VALUE, &parmKey);
1002 if (code == ERROR_SUCCESS) {
1003 dummyLen = sizeof(verifyServiceSig);
1004 code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
1005 (BYTE *) &verifyServiceSig, &dummyLen);
1006 RegCloseKey (parmKey);
1009 if (verifyServiceSig
1011 && cacheSize < 716800
1014 trustVerified = VerifyTrust(filename);
1016 afsi_log("Signature Verification disabled");
1019 if (trustVerified) {
1022 // get a certificate context for the signer of afsd_service.
1023 pCtxService = GetCertCtx(filename);
1025 LogCertCtx(pCtxService);
1028 // Get a list of all the modules in this process.
1029 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1030 FALSE, GetCurrentProcessId());
1032 if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1034 afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1036 for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1038 char szModName[2048];
1040 // Get the full path to the module's file.
1041 if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1043 lstrcpy(checkName, szModName);
1046 if ( strstr(checkName, "afspthread.dll") ||
1047 strstr(checkName, "afsauthent.dll") ||
1048 strstr(checkName, "afsrpc.dll") ||
1049 strstr(checkName, "libafsconf.dll") ||
1050 strstr(checkName, "libosi.dll") )
1052 if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1057 afsi_log("%s version %s", szModName, modVersion);
1058 if (strcmp(afsdVersion,modVersion)) {
1059 afsi_log("Version mismatch: %s", szModName);
1062 if ( trustVerified ) {
1063 if ( !VerifyTrust(szModName) ) {
1064 afsi_log("Signature Verification failed: %s", szModName);
1067 else if (pCtxService) {
1068 PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1070 if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1071 pCtxService->pCertInfo,
1073 afsi_log("Certificate mismatch: %s", szModName);
1081 pCertFreeCertificateContext(pCtx);
1090 pCertFreeCertificateContext(pCtxService);
1094 FreeLibrary(hPSAPI);
1096 CloseHandle(hProcess);
1101 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1104 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1105 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION );
1107 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1108 RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
1111 afsd_Main(DWORD argc, LPTSTR *argv)
1125 afsd_DbgBreakAllocInit();
1126 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
1127 _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1130 afsd_SetUnhandledExceptionFilter();
1132 osi_InitPanic(afsd_notifier);
1133 osi_InitTraceOption();
1139 WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1140 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1141 afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1144 hAdvApi32 = LoadLibrary("advapi32.dll");
1145 if (hAdvApi32 == NULL)
1147 afsi_log("Fatal: cannot load advapi32.dll");
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);
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 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1206 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1207 ServiceStatus.dwCheckPoint = 0;
1208 ServiceStatus.dwWaitHint = 0;
1209 ServiceStatus.dwControlsAccepted = 0;
1210 SetServiceStatus(StatusHandle, &ServiceStatus);
1212 LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1214 /* exit if initialization failed */
1218 /* allow an exit to be called prior to any initialization */
1219 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1223 AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1226 hookRc = initHook();
1228 FreeLibrary(hHookDll);
1231 if (hookRc == FALSE)
1233 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1234 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1235 ServiceStatus.dwCheckPoint = 0;
1236 ServiceStatus.dwWaitHint = 0;
1237 ServiceStatus.dwControlsAccepted = 0;
1238 SetServiceStatus(StatusHandle, &ServiceStatus);
1240 /* exit if initialization failed */
1245 /* allow another 120 seconds to start */
1246 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1247 ServiceStatus.dwServiceSpecificExitCode = 0;
1248 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1249 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1250 ServiceStatus.dwCheckPoint = 2;
1251 ServiceStatus.dwWaitHint = 120000;
1252 /* accept Power Events */
1253 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1254 SetServiceStatus(StatusHandle, &ServiceStatus);
1258 /* Perform Volume Status Notification Initialization */
1259 cm_VolStatus_Initialization();
1262 MainThreadId = GetCurrentThreadId();
1263 jmpret = setjmp(notifier_jmp);
1268 code = afsd_InitCM(&reason);
1270 afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1271 osi_panic(reason, __FILE__, __LINE__);
1275 ServiceStatus.dwCheckPoint = 3;
1276 ServiceStatus.dwWaitHint = 30000;
1277 SetServiceStatus(StatusHandle, &ServiceStatus);
1279 code = afsd_InitDaemons(&reason);
1281 afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1282 osi_panic(reason, __FILE__, __LINE__);
1285 /* allow an exit to be called post rx initialization */
1286 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1290 AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1293 hookRc = rxStartedHook();
1295 FreeLibrary(hHookDll);
1298 if (hookRc == FALSE)
1300 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1301 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1302 ServiceStatus.dwCheckPoint = 0;
1303 ServiceStatus.dwWaitHint = 0;
1304 ServiceStatus.dwControlsAccepted = 0;
1305 SetServiceStatus(StatusHandle, &ServiceStatus);
1307 /* exit if initialization failed */
1313 ServiceStatus.dwCheckPoint = 4;
1314 ServiceStatus.dwWaitHint = 15000;
1315 SetServiceStatus(StatusHandle, &ServiceStatus);
1318 /* Notify any volume status handlers that the cache manager has started */
1319 cm_VolStatus_Service_Started();
1321 /* the following ifdef chooses the mode of operation for the service. to enable
1322 * a runtime flag (instead of compile-time), pioctl() would need to dynamically
1323 * determine the mode, in order to use the correct ioctl special-file path. */
1325 code = afsd_InitSMB(&reason, MessageBox);
1327 afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1328 osi_panic(reason, __FILE__, __LINE__);
1331 code = ifs_Init(&reason);
1333 afsi_log("ifs_Init failed: %s (code = %d)", reason, code);
1334 osi_panic(reason, __FILE__, __LINE__);
1336 for (cnt = 0; cnt < WORKER_THREADS; cnt++)
1337 hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL);
1340 /* allow an exit to be called post smb initialization */
1341 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1345 AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1348 hookRc = smbStartedHook();
1350 FreeLibrary(hHookDll);
1353 if (hookRc == FALSE)
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 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1371 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1372 ServiceStatus.dwCheckPoint = 5;
1373 ServiceStatus.dwWaitHint = 0;
1375 /* accept Power events */
1376 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1377 SetServiceStatus(StatusHandle, &ServiceStatus);
1380 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1383 /* allow an exit to be called when started */
1384 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1388 AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1391 hookRc = startedHook();
1393 FreeLibrary(hHookDll);
1396 if (hookRc == FALSE)
1398 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1399 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1400 ServiceStatus.dwCheckPoint = 0;
1401 ServiceStatus.dwWaitHint = 0;
1402 ServiceStatus.dwControlsAccepted = 0;
1403 SetServiceStatus(StatusHandle, &ServiceStatus);
1405 /* exit if initialization failed */
1411 WaitForSingleObject(WaitToTerminate, INFINITE);
1413 WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
1414 for (cnt = 0; cnt < WORKER_THREADS; cnt++)
1415 CloseHandle(hAFSDWorkerThread[cnt]);
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 = LoadLibrary(AFSD_HOOK_DLL);
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");
1455 cm_DaemonShutdown();
1456 afsi_log("Daemon shutdown complete");
1461 afsi_log("Buffer shutdown complete");
1464 afsi_log("rx finalization complete");
1468 afsi_log("smb shutdown complete");
1473 cm_ReleaseAllLocks();
1476 afsi_log("rx finalization complete");
1478 cm_ShutdownMappedMemory();
1480 #ifdef REGISTER_POWER_NOTIFICATIONS
1481 /* terminate thread used to flush cache */
1482 if (powerEventsRegistered)
1483 PowerNotificationThreadExit();
1488 cm_BPlusDumpStats();
1491 /* Notify any Volume Status Handlers that we are stopped */
1492 cm_VolStatus_Service_Stopped();
1494 /* Cleanup any Volume Status Notification Handler */
1495 cm_VolStatus_Finalize();
1497 /* allow an exit to be called after stopping the service */
1498 hHookDll = LoadLibrary(AFSD_HOOK_DLL);
1502 AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1505 hookRc = stoppedHook();
1507 FreeLibrary(hHookDll);
1511 /* Remove the ExceptionFilter */
1512 SetUnhandledExceptionFilter(NULL);
1514 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1515 ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1516 ServiceStatus.dwCheckPoint = 7;
1517 ServiceStatus.dwWaitHint = 0;
1518 ServiceStatus.dwControlsAccepted = 0;
1519 SetServiceStatus(StatusHandle, &ServiceStatus);
1522 DWORD __stdcall afsdMain_thread(void* notUsed)
1524 char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1525 afsd_Main(1, (LPTSTR*)argv);
1531 fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1535 main(int argc, char * argv[])
1537 static SERVICE_TABLE_ENTRY dispatchTable[] = {
1538 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1543 for (i = 1; i < argc; i++) {
1544 if (!stricmp(argv[i],"--validate-cache")) {
1545 if (++i != argc - 1) {
1550 return cm_ValidateMappedMemory(argv[i]);
1557 if (!StartServiceCtrlDispatcher(dispatchTable))
1559 LONG status = GetLastError();
1560 if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1563 hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1565 printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1567 SetEvent(WaitToTerminate);
1574 if ( hAFSDMainThread ) {
1575 WaitForSingleObject( hAFSDMainThread, INFINITE );
1576 CloseHandle( hAFSDMainThread );