/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #include #include #include #include #include #include #include #include "afsd.h" #include "afsd_init.h" #include #include #include #include #ifdef DEBUG //#define NOTSERVICE #endif #ifdef _DEBUG #include #endif /* // The following is defined if you want to receive Power notifications, // including Hibernation, and also subsequent flushing of AFS volumes // #define REGISTER_POWER_NOTIFICATIONS 1 #define FLUSH_VOLUME 1 // // Check */ #include "afsd_flushvol.h" extern void afsi_log(char *pattern, ...); HANDLE hAFSDMainThread = NULL; HANDLE WaitToTerminate; int GlobalStatus; #ifdef JUMP unsigned int MainThreadId; jmp_buf notifier_jmp; #endif /* JUMP */ extern int traceOnPanic; extern HANDLE afsi_file; int powerEventsRegistered = 0; /* * Notifier function for use by osi_panic */ static void afsd_notifier(char *msgp, char *filep, long line) { char tbuffer[512]; char *ptbuf[1]; HANDLE h; if (filep) sprintf(tbuffer, "Error at file %s, line %d: %s", filep, line, msgp); else sprintf(tbuffer, "Error at unknown location: %s", msgp); h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME); ptbuf[0] = tbuffer; ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL); DeregisterEventSource(h); GlobalStatus = line; osi_LogEnable(afsd_logp); afsd_ForceTrace(TRUE); buf_ForceTrace(TRUE); afsi_log("--- begin dump ---"); cm_DumpSCache(afsi_file, "a"); #ifdef keisa cm_dnlcDump(afsi_file, "a"); #endif cm_DumpBufHashTable(afsi_file, "a"); smb_DumpVCP(afsi_file, "a"); afsi_log("--- end dump ---"); DebugBreak(); SetEvent(WaitToTerminate); #ifdef JUMP if (GetCurrentThreadId() == MainThreadId) longjmp(notifier_jmp, 1); else #endif /* JUMP */ ExitThread(1); } /* * For use miscellaneously in smb.c; need to do better */ static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui) { return 0; } static SERVICE_STATUS ServiceStatus; static SERVICE_STATUS_HANDLE StatusHandle; DWORD afsd_ServiceFlushVolume(DWORD dwlpEventData) { DWORD dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */ /* ** If UI bit is not set, user interaction is not possible ** BUT, since we are a NON-interactive service, and therefore ** have NO user I/O, it doesn't much matter. ** This benign code left here as example of how to find this out */ BOOL bUI = (dwlpEventData & 1); /* flush volume */ if ( PowerNotificationThreadNotify() ) { dwRet = NO_ERROR; } else { /* flush was unsuccessful, or timeout - deny shutdown */ dwRet = ERROR_NETWORK_BUSY; } /* to deny hibernate, simply return // any value besides NO_ERROR. // For example: // dwRet = ERROR_NETWORK_BUSY; */ return dwRet; } /* service control handler used in nt4 only for backward compat. */ VOID WINAPI afsd_ServiceControlHandler(DWORD ctrlCode) { HKEY parmKey; DWORD dummyLen, doTrace; long code; switch (ctrlCode) { case SERVICE_CONTROL_STOP: /* Shutdown RPC */ RpcMgmtStopServerListening(NULL); /* Force trace if requested */ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code != ERROR_SUCCESS) goto doneTrace; dummyLen = sizeof(doTrace); code = RegQueryValueEx(parmKey, "TraceOnShutdown", NULL, NULL, (BYTE *) &doTrace, &dummyLen); RegCloseKey (parmKey); if (code != ERROR_SUCCESS) doTrace = 0; if (doTrace) { afsd_ForceTrace(FALSE); buf_ForceTrace(FALSE); } doneTrace: ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 1; ServiceStatus.dwWaitHint = 10000; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; SetServiceStatus(StatusHandle, &ServiceStatus); SetEvent(WaitToTerminate); break; case SERVICE_CONTROL_INTERROGATE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; SetServiceStatus(StatusHandle, &ServiceStatus); break; /* XXX handle system shutdown */ /* XXX handle pause & continue */ } } /* ** Extended ServiceControlHandler that provides Event types ** for monitoring Power events, for example. */ DWORD WINAPI afsd_ServiceControlHandlerEx( DWORD ctrlCode, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) { HKEY parmKey; DWORD dummyLen, doTrace; long code; DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED; switch (ctrlCode) { case SERVICE_CONTROL_STOP: /* Shutdown RPC */ RpcMgmtStopServerListening(NULL); /* Force trace if requested */ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code != ERROR_SUCCESS) goto doneTrace; dummyLen = sizeof(doTrace); code = RegQueryValueEx(parmKey, "TraceOnShutdown", NULL, NULL, (BYTE *) &doTrace, &dummyLen); RegCloseKey (parmKey); if (code != ERROR_SUCCESS) doTrace = 0; if (doTrace) { afsd_ForceTrace(FALSE); buf_ForceTrace(FALSE); } doneTrace: ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 1; ServiceStatus.dwWaitHint = 10000; ServiceStatus.dwControlsAccepted = 0; SetServiceStatus(StatusHandle, &ServiceStatus); SetEvent(WaitToTerminate); dwRet = NO_ERROR; break; case SERVICE_CONTROL_INTERROGATE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT; SetServiceStatus(StatusHandle, &ServiceStatus); dwRet = NO_ERROR; break; /* XXX handle system shutdown */ /* XXX handle pause & continue */ case SERVICE_CONTROL_POWEREVENT: { /* ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST ** Return NO_ERROR == return TRUE for that message, i.e. accept request ** Return any error code to deny request, ** i.e. as if returning BROADCAST_QUERY_DENY */ if (powerEventsRegistered) { switch((int) dwEventType) { case PBT_APMQUERYSUSPEND: case PBT_APMQUERYSTANDBY: #ifdef FLUSH_VOLUME /* handle event */ dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData); #else dwRet = NO_ERROR; #endif break; /* allow remaining case PBT_WhatEver */ case PBT_APMSUSPEND: case PBT_APMSTANDBY: case PBT_APMRESUMECRITICAL: case PBT_APMRESUMESUSPEND: case PBT_APMRESUMESTANDBY: case PBT_APMBATTERYLOW: case PBT_APMPOWERSTATUSCHANGE: case PBT_APMOEMEVENT: case PBT_APMRESUMEAUTOMATIC: default: dwRet = NO_ERROR; } } } } /* end switch(ctrlCode) */ return dwRet; } /* There is similar code in client_config\drivemap.cpp GlobalMountDrive() * * Mount a drive into AFS if there global mapping */ /* DEE Could check first if we are run as SYSTEM */ #define MAX_RETRIES 30 static void MountGlobalDrives(void) { char szAfsPath[_MAX_PATH]; char szDriveToMapTo[5]; DWORD dwResult; char szKeyName[256]; HKEY hKey; DWORD dwIndex = 0, dwRetry = 0; DWORD dwDriveSize; DWORD dwSubMountSize; char szSubMount[256]; DWORD dwType; sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName); dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey); if (dwResult != ERROR_SUCCESS) return; while (dwRetry < MAX_RETRIES) { dwDriveSize = sizeof(szDriveToMapTo); dwSubMountSize = sizeof(szSubMount); dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize); if (dwResult != ERROR_MORE_DATA) { if (dwResult != ERROR_SUCCESS) { if (dwResult != ERROR_NO_MORE_ITEMS) afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult); break; } } for ( ; dwRetry < MAX_RETRIES; dwRetry++) { NETRESOURCE nr; memset (&nr, 0x00, sizeof(NETRESOURCE)); sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount); nr.dwScope = RESOURCE_GLOBALNET; /* ignored parameter */ nr.dwType=RESOURCETYPE_DISK; nr.lpLocalName=szDriveToMapTo; nr.lpRemoteName=szAfsPath; nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */ nr.dwUsage = RESOURCEUSAGE_CONNECTABLE; /* ignored parameter */ dwResult = WNetAddConnection2(&nr,NULL,NULL,0); afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount, (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult); if (dwResult == NO_ERROR) { break; } /* wait for smb server to come up */ Sleep((DWORD)1000 /* miliseconds */); /* Disconnect any previous mappings */ dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE); } } RegCloseKey(hKey); } static void DismountGlobalDrives() { char szAfsPath[_MAX_PATH]; char szDriveToMapTo[5]; DWORD dwResult; char szKeyName[256]; HKEY hKey; DWORD dwIndex = 0; DWORD dwDriveSize; DWORD dwSubMountSize; char szSubMount[256]; DWORD dwType; sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName); dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey); if (dwResult != ERROR_SUCCESS) return; while (1) { dwDriveSize = sizeof(szDriveToMapTo); dwSubMountSize = sizeof(szSubMount); dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize); if (dwResult != ERROR_MORE_DATA) { if (dwResult != ERROR_SUCCESS) { if (dwResult != ERROR_NO_MORE_ITEMS) afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult); break; } } sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount); dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE); dwResult = WNetCancelConnection(szAfsPath, TRUE); afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed"); } RegCloseKey(hKey); } DWORD GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput ) { DWORD dwVersionHandle; LPVOID pVersionInfo = 0; DWORD retval = 0; LPDWORD pLangInfo = 0; LPTSTR szVersion = 0; UINT len = 0; TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion"); DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle); if (!size) { afsi_log("GetFileVersionInfoSize failed"); return GetLastError(); } pVersionInfo = malloc(size); if (!pVersionInfo) { afsi_log("out of memory 1"); return ERROR_NOT_ENOUGH_MEMORY; } GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo); if (retval = GetLastError()) { afsi_log("GetFileVersionInfo failed: %d", retval); goto cleanup; } VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pLangInfo, &len); if (retval = GetLastError()) { afsi_log("VerQueryValue 1 failed: %d", retval); goto cleanup; } wsprintf(szVerQ, TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), LOWORD(*pLangInfo), HIWORD(*pLangInfo)); VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len); if (retval = GetLastError()) { /* try again with language 409 since the old binaries were tagged wrong */ wsprintf(szVerQ, TEXT("\\StringFileInfo\\0409%04x\\FileVersion"), HIWORD(*pLangInfo)); VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len); if (retval = GetLastError()) { afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval); goto cleanup; } } snprintf(szOutput, dwOutput, TEXT("%s"), szVersion); szOutput[dwOutput - 1] = 0; cleanup: if (pVersionInfo) free(pVersionInfo); return retval; } BOOL VerifyTrust(CHAR * filename) { WINTRUST_DATA fTrust; WINTRUST_FILE_INFO finfo; GUID trustAction = WINTRUST_ACTION_GENERIC_VERIFY_V2; GUID subject = WIN_TRUST_SUBJTYPE_RAW_FILEEX; wchar_t wfilename[260]; LONG ret; if (filename == NULL ) return FALSE; mbstowcs(wfilename, filename, 260); finfo.cbStruct = sizeof(finfo); finfo.pcwszFilePath= wfilename; finfo.hFile = INVALID_HANDLE_VALUE; finfo.pgKnownSubject = &subject; fTrust.cbStruct = sizeof(fTrust); fTrust.pPolicyCallbackData = NULL; fTrust.pSIPClientData = NULL; fTrust.dwUIChoice = WTD_UI_NONE; fTrust.fdwRevocationChecks = WTD_REVOKE_NONE; fTrust.dwUnionChoice = WTD_CHOICE_FILE; fTrust.pFile = &finfo; fTrust.dwStateAction = WTD_STATEACTION_IGNORE; fTrust.hWVTStateData = NULL; fTrust.pwszURLReference = NULL; fTrust.dwProvFlags = WTD_SAFER_FLAG | WTD_REVOCATION_CHECK_NONE; fTrust.dwUIContext = WTD_UICONTEXT_EXECUTE; ret = WinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, &fTrust); if (ret == ERROR_SUCCESS) { return TRUE; } else { DWORD gle = GetLastError(); switch (gle) { case TRUST_E_PROVIDER_UNKNOWN: afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown"); break; case TRUST_E_NOSIGNATURE: afsi_log("VerifyTrust failed: Unsigned executable"); break; case TRUST_E_EXPLICIT_DISTRUST: afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user"); break; case TRUST_E_SUBJECT_NOT_TRUSTED: afsi_log("VerifyTrust failed: File is not trusted"); break; case CRYPT_E_SECURITY_SETTINGS: afsi_log("VerifyTrust failed: local security options prevent verification"); break; default: afsi_log("VerifyTrust failed: 0x%X", GetLastError()); } return FALSE; } } BOOL AFSModulesVerify(void) { CHAR filename[1024]; CHAR afsdVersion[128]; CHAR modVersion[128]; CHAR checkName[1024]; BOOL trustVerified = FALSE; HMODULE hMods[1024]; HANDLE hProcess; DWORD cbNeeded; unsigned int i; BOOL success = TRUE; if (!GetModuleFileName(NULL, filename, sizeof(filename))) return FALSE; if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion))) return FALSE; afsi_log("%s version %s", filename, afsdVersion); trustVerified = VerifyTrust(filename); // Get a list of all the modules in this process. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE))); for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { char szModName[2048]; // Get the full path to the module's file. if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName))) { lstrcpy(checkName, szModName); strlwr(checkName); if ( strstr(checkName, "afspthread.dll") || strstr(checkName, "afsauthent.dll") || strstr(checkName, "afsrpc.dll") || strstr(checkName, "libafsconf.dll") || strstr(checkName, "libosi.dll") ) { if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) { success = FALSE; continue; } afsi_log("%s version %s", szModName, modVersion); if (strcmp(afsdVersion,modVersion)) { afsi_log("Version mismatch: %s", szModName); success = FALSE; } if ( trustVerified && !VerifyTrust(szModName) ) { afsi_log("Signature Verification failed: %s", szModName); success = FALSE; } } } } } CloseHandle(hProcess); return success; } typedef BOOL ( APIENTRY * AfsdInitHook )(void); #define AFSD_INIT_HOOK "AfsdInitHook" #define AFSD_HOOK_DLL "afsdhook.dll" /* control serviceex exists only on 2000/xp. These functions will be loaded dynamically. */ typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )( LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID ); typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc )( LPCTSTR , LPHANDLER_FUNCTION ); RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL; RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL; void afsd_Main(DWORD argc, LPTSTR *argv) { long code; char *reason; #ifdef JUMP int jmpret; #endif /* JUMP */ HANDLE hInitHookDll; HANDLE hAdvApi32; AfsdInitHook initHook; #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ ); #endif osi_InitPanic(afsd_notifier); osi_InitTraceOption(); GlobalStatus = 0; afsi_start(); WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate")); if ( GetLastError() == ERROR_ALREADY_EXISTS ) afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate")); #ifndef NOTSERVICE hAdvApi32 = LoadLibrary("advapi32.dll"); if (hAdvApi32 == NULL) { afsi_log("Fatal: cannot load advapi32.dll"); return; } pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA"); if (pRegisterServiceCtrlHandlerEx) { afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx"); StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL ); } else { StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler); } ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 1; ServiceStatus.dwWaitHint = 30000; /* accept Power Events */ ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT; SetServiceStatus(StatusHandle, &ServiceStatus); #endif { HANDLE h; char *ptbuf[1]; h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME); ptbuf[0] = "AFS start pending"; ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL); DeregisterEventSource(h); } #ifdef REGISTER_POWER_NOTIFICATIONS { HKEY hkParm; DWORD code; DWORD dummyLen; int bpower = TRUE; /* see if we should handle power notifications */ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &hkParm); if (code == ERROR_SUCCESS) { dummyLen = sizeof(bpower); code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL, (BYTE *) &bpower, &dummyLen); if(code != ERROR_SUCCESS) bpower = TRUE; RegCloseKey(hkParm); } /* create thread used to flush cache */ if (bpower) { PowerNotificationThreadCreate(); powerEventsRegistered = 1; } } #endif /* Verify the versions of the DLLs which were loaded */ if (!AFSModulesVerify()) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwControlsAccepted = 0; SetServiceStatus(StatusHandle, &ServiceStatus); /* exit if initialization failed */ return; } /* allow an exit to be called prior to any initialization */ hInitHookDll = LoadLibrary(AFSD_HOOK_DLL); if (hInitHookDll) { BOOL hookRc = FALSE; initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK); if (initHook) { hookRc = initHook(); } FreeLibrary(hInitHookDll); hInitHookDll = NULL; if (hookRc == FALSE) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwControlsAccepted = 0; SetServiceStatus(StatusHandle, &ServiceStatus); /* exit if initialization failed */ return; } else { /* allow another 15 seconds to start */ ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 2; ServiceStatus.dwWaitHint = 20000; /* accept Power Events */ ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT; SetServiceStatus(StatusHandle, &ServiceStatus); } } #ifdef JUMP MainThreadId = GetCurrentThreadId(); jmpret = setjmp(notifier_jmp); if (jmpret == 0) #endif /* JUMP */ { code = afsd_InitCM(&reason); if (code != 0) { afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code); osi_panic(reason, __FILE__, __LINE__); } #ifndef NOTSERVICE ServiceStatus.dwCheckPoint++; ServiceStatus.dwWaitHint -= 5000; SetServiceStatus(StatusHandle, &ServiceStatus); #endif code = afsd_InitDaemons(&reason); if (code != 0) { afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code); osi_panic(reason, __FILE__, __LINE__); } #ifndef NOTSERVICE ServiceStatus.dwCheckPoint++; ServiceStatus.dwWaitHint -= 5000; SetServiceStatus(StatusHandle, &ServiceStatus); #endif code = afsd_InitSMB(&reason, MessageBox); if (code != 0) { afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code); osi_panic(reason, __FILE__, __LINE__); } MountGlobalDrives(); #ifndef NOTSERVICE ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; /* accept Power events */ ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT; SetServiceStatus(StatusHandle, &ServiceStatus); #endif { HANDLE h; char *ptbuf[1]; h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME); ptbuf[0] = "AFS running"; ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL); DeregisterEventSource(h); } } WaitForSingleObject(WaitToTerminate, INFINITE); { HANDLE h; char *ptbuf[1]; h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME); ptbuf[0] = "AFS quitting"; ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL); DeregisterEventSource(h); } DismountGlobalDrives(); smb_Shutdown(); rx_Finalize(); #ifdef REGISTER_POWER_NOTIFICATIONS /* terminate thread used to flush cache */ if (powerEventsRegistered) PowerNotificationThreadExit(); #endif /* Remove the ExceptionFilter */ SetUnhandledExceptionFilter(NULL); ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwControlsAccepted = 0; SetServiceStatus(StatusHandle, &ServiceStatus); } DWORD __stdcall afsdMain_thread(void* notUsed) { char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL}; afsd_Main(1, (LPTSTR*)argv); return(0); } int main(void) { static SERVICE_TABLE_ENTRY dispatchTable[] = { {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main}, {NULL, NULL} }; if (!StartServiceCtrlDispatcher(dispatchTable)) { LONG status = GetLastError(); if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { DWORD tid; hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid); printf("Hit to terminate OpenAFS Client Service\n"); getchar(); SetEvent(WaitToTerminate); } } if ( hAFSDMainThread ) { WaitForSingleObject( hAFSDMainThread, INFINITE ); CloseHandle( hAFSDMainThread ); } return(0); }