windows-hooks-20050418
[openafs.git] / src / WINNT / afsd / afsd_service.c
index 506c864..4e115d1 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <winsock2.h>
+#include <WINNT\afsreg.h>
 
 #include <osi.h>
 
 #include <crtdbg.h>
 #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
-*/
+//#define REGISTER_POWER_NOTIFICATIONS 1
 #include "afsd_flushvol.h"
 
 extern void afsi_log(char *pattern, ...);
 
+static SERVICE_STATUS          ServiceStatus;
+static SERVICE_STATUS_HANDLE   StatusHandle;
+
 HANDLE hAFSDMainThread = NULL;
 
 HANDLE WaitToTerminate;
@@ -88,12 +84,12 @@ static void afsd_notifier(char *msgp, char *filep, long line)
     buf_ForceTrace(TRUE);
 
     afsi_log("--- begin dump ---");
-    cm_DumpSCache(afsi_file, "a");
+    cm_DumpSCache(afsi_file, "a", 0);
 #ifdef keisa
     cm_dnlcDump(afsi_file, "a");
 #endif
-    cm_DumpBufHashTable(afsi_file, "a");
-    smb_DumpVCP(afsi_file, "a");                       
+    cm_DumpBufHashTable(afsi_file, "a", 0);
+    smb_DumpVCP(afsi_file, "a", 0);                    
     afsi_log("--- end   dump ---");
     
 #ifdef DEBUG
@@ -105,9 +101,16 @@ static void afsd_notifier(char *msgp, char *filep, long line)
 #ifdef JUMP
     if (GetCurrentThreadId() == MainThreadId)
         longjmp(notifier_jmp, 1);
-    else
 #endif /* JUMP */
-        ExitThread(1);
+
+    ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+    ServiceStatus.dwCheckPoint = 0;
+    ServiceStatus.dwWaitHint = 0;
+    ServiceStatus.dwControlsAccepted = 0;
+    SetServiceStatus(StatusHandle, &ServiceStatus);
+
+    exit(1);
 }
 
 /*
@@ -118,9 +121,6 @@ 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)
 {
@@ -164,13 +164,26 @@ afsd_ServiceControlHandler(DWORD ctrlCode)
     long code;
 
     switch (ctrlCode) {
+    case SERVICE_CONTROL_SHUTDOWN:
     case SERVICE_CONTROL_STOP:
-        /* Shutdown RPC */
-        RpcMgmtStopServerListening(NULL);
+        ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+        ServiceStatus.dwWin32ExitCode = NO_ERROR;
+        ServiceStatus.dwCheckPoint = 1;
+        ServiceStatus.dwWaitHint = 30000;
+        ServiceStatus.dwControlsAccepted = 0;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+
+        if (ctrlCode == SERVICE_CONTROL_STOP)
+            afsi_log("SERVICE_CONTROL_STOP");
+        else
+            afsi_log("SERVICE_CONTROL_SHUTDOWN");
+
+        /* Write all dirty buffers back to server */
+        buf_CleanAndReset();
 
         /* Force trace if requested */
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                             AFSConfigKeyName,
+                             AFSREG_CLT_SVC_PARAM_SUBKEY,
                              0, KEY_QUERY_VALUE, &parmKey);
         if (code != ERROR_SUCCESS)
             goto doneTrace;
@@ -188,20 +201,15 @@ afsd_ServiceControlHandler(DWORD ctrlCode)
         }
 
       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;
+        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
         SetServiceStatus(StatusHandle, &ServiceStatus);
         break;
         /* XXX handle system shutdown */
@@ -229,13 +237,21 @@ afsd_ServiceControlHandlerEx(
 
     switch (ctrlCode) 
     {
+    case SERVICE_CONTROL_SHUTDOWN:
     case SERVICE_CONTROL_STOP:
-        /* Shutdown RPC */
-        RpcMgmtStopServerListening(NULL);
+        ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+        ServiceStatus.dwWin32ExitCode = NO_ERROR;
+        ServiceStatus.dwCheckPoint = 1;
+        ServiceStatus.dwWaitHint = 30000;
+        ServiceStatus.dwControlsAccepted = 0;
+        SetServiceStatus(StatusHandle, &ServiceStatus);
+
+        /* Write all dirty buffers back to server */
+        buf_CleanAndReset();
 
         /* Force trace if requested */
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                            AFSConfigKeyName,
+                            AFSREG_CLT_SVC_PARAM_SUBKEY,
                             0, KEY_QUERY_VALUE, &parmKey);
         if (code != ERROR_SUCCESS)
             goto doneTrace;
@@ -253,12 +269,6 @@ afsd_ServiceControlHandlerEx(
         }
 
       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;
@@ -268,15 +278,17 @@ afsd_ServiceControlHandlerEx(
         ServiceStatus.dwWin32ExitCode = NO_ERROR;
         ServiceStatus.dwCheckPoint = 0;
         ServiceStatus.dwWaitHint = 0;
-        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
+        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
         SetServiceStatus(StatusHandle, &ServiceStatus);
+        afsi_log("SERVICE_CONTROL_INTERROGATE");
         dwRet = NO_ERROR;
         break;
 
         /* XXX handle system shutdown */
         /* XXX handle pause & continue */
     case SERVICE_CONTROL_POWEREVENT:                                              
-        {                                                                                     
+        { 
+            afsi_log("SERVICE_CONTROL_POWEREVENT");
             /*                                                                                
             ** dwEventType of this notification == WPARAM of WM_POWERBROADCAST               
             ** Return NO_ERROR == return TRUE for that message, i.e. accept request          
@@ -286,29 +298,59 @@ afsd_ServiceControlHandlerEx(
             if (powerEventsRegistered) {
                 switch((int) dwEventType)                                                         
                 {                                                                               
-                case PBT_APMQUERYSUSPEND:                                                         
+                case PBT_APMQUERYSUSPEND:       
+                    afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND"); 
+                    /* Write all dirty buffers back to server */
+                    buf_CleanAndReset();
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMQUERYSTANDBY:                                                         
-
-#ifdef FLUSH_VOLUME
-                    /* handle event */                                                            
-                    dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);                         
-#else                                                                                       
+                    afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY"); 
+                    /* Write all dirty buffers back to server */
+                    buf_CleanAndReset();
                     dwRet = NO_ERROR;                                                             
-#endif                                                                                      
                     break;                                                                        
                                                                                                                          
                     /* allow remaining case PBT_WhatEver */                                           
-                case PBT_APMSUSPEND:                                                              
-                case PBT_APMSTANDBY:                                                              
-                case PBT_APMRESUMECRITICAL:                                                       
+                case PBT_APMSUSPEND:                         
+                    afsi_log("SERVICE_CONTROL_APMSUSPEND"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
+                case PBT_APMSTANDBY:                  
+                    afsi_log("SERVICE_CONTROL_APMSTANDBY"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
+                case PBT_APMRESUMECRITICAL:             
+                    afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMRESUMESUSPEND:                                                        
+                    afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMRESUMESTANDBY:                                                        
+                    afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMBATTERYLOW:                                                           
+                    afsi_log("SERVICE_CONTROL_APMBATTERYLOW"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMPOWERSTATUSCHANGE:                                                    
+                    afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMOEMEVENT:                                                             
+                    afsi_log("SERVICE_CONTROL_APMOEMEVENT"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 case PBT_APMRESUMEAUTOMATIC:                                                      
+                    afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC"); 
+                    dwRet = NO_ERROR;                       
+                    break;                                  
                 default:                                                                          
-                    dwRet = NO_ERROR;                                                             
+                    afsi_log("SERVICE_CONTROL_unknown"); 
+                    dwRet = NO_ERROR;                       
                 }   
             }
         }
@@ -335,7 +377,7 @@ static void MountGlobalDrives(void)
     char szSubMount[256];
     DWORD dwType;
 
-    sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
+    sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
 
     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
     if (dwResult != ERROR_SUCCESS)
@@ -397,7 +439,7 @@ static void DismountGlobalDrives()
     char szSubMount[256];
     DWORD dwType;
 
-    sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
+    sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
 
     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
     if (dwResult != ERROR_SUCCESS)
@@ -492,6 +534,60 @@ GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
     return retval;
 }
 
+static HINSTANCE hCrypt32;
+static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext,  DWORD dwType,  DWORD dwFlags,
+                                          void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
+static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
+                                        DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
+                                        DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
+                                        DWORD* pdwFormatType, HCERTSTORE* phCertStore,
+                                        HCRYPTMSG* phMsg, const void** ppvContext);
+static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
+                                        void* pvData, DWORD* pcbData);
+static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
+                                                            DWORD dwFindFlags, DWORD dwFindType,
+                                                            const void* pvFindPara,
+                                                            PCCERT_CONTEXT pPrevCertContext);
+static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
+static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
+static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
+                                              PCERT_INFO pCertId2);
+static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
+
+void LoadCrypt32(void)
+{
+    hCrypt32 = LoadLibrary("crypt32");
+    if ( !hCrypt32 )
+        return;
+
+    (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
+    (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
+    (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
+    (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
+    (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
+    (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
+    (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
+    (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
+    
+    if ( !pCertGetNameString ||
+         !pCryptQueryObject ||
+         !pCryptMsgGetParam ||
+         !pCertFindCertificateInStore ||
+         !pCertCloseStore ||
+         !pCryptMsgClose ||
+         !pCertCompareCertificate ||
+         !pCertFreeCertificateContext)
+    {
+        FreeLibrary(hCrypt32);
+        hCrypt32 = NULL;
+    }
+}
+
+void UnloadCrypt32(void)
+{
+    FreeLibrary(hCrypt32);
+}
+
 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
 
 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
@@ -508,20 +604,23 @@ PCCERT_CONTEXT GetCertCtx(CHAR * filename)
     PCCERT_CONTEXT pCertContext = NULL;
     CERT_INFO CertInfo;
 
+    if ( hCrypt32 == NULL )
+        return NULL;
+
     ZeroMemory(&CertInfo, sizeof(CertInfo));
     mbstowcs(wfilename, filename, 260);
 
-    fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
-                              wfilename,
-                              CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
-                              CERT_QUERY_FORMAT_FLAG_BINARY,
-                              0,
-                              &dwEncoding,
-                              &dwContentType,
-                              &dwFormatType,
-                              &hStore,
-                              &hMsg,
-                              NULL);
+    fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
+                               wfilename,
+                               CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+                               CERT_QUERY_FORMAT_FLAG_BINARY,
+                               0,
+                               &dwEncoding,
+                               &dwContentType,
+                               &dwFormatType,
+                               &hStore,
+                               &hMsg,
+                               NULL);
 
     if (!fResult) {
         afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
@@ -530,11 +629,11 @@ PCCERT_CONTEXT GetCertCtx(CHAR * filename)
        goto __exit;
     }
 
-    fResult = CryptMsgGetParam(hMsg,
-                              CMSG_SIGNER_INFO_PARAM,
-                              0,
-                              NULL,
-                              &dwSignerInfo);
+    fResult = pCryptMsgGetParam(hMsg,
+                               CMSG_SIGNER_INFO_PARAM,
+                               0,
+                               NULL,
+                               &dwSignerInfo);
 
     if (!fResult) {
         afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
@@ -545,11 +644,11 @@ PCCERT_CONTEXT GetCertCtx(CHAR * filename)
 
     pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
 
-    fResult = CryptMsgGetParam(hMsg,
-                              CMSG_SIGNER_INFO_PARAM,
-                              0,
-                              (PVOID)pSignerInfo,
-                              &dwSignerInfo);
+    fResult = pCryptMsgGetParam(hMsg,
+                               CMSG_SIGNER_INFO_PARAM,
+                               0,
+                               (PVOID)pSignerInfo,
+                               &dwSignerInfo);
     
     if (!fResult) {
         afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
@@ -561,7 +660,7 @@ PCCERT_CONTEXT GetCertCtx(CHAR * filename)
     CertInfo.Issuer = pSignerInfo->Issuer;
     CertInfo.SerialNumber = pSignerInfo->SerialNumber;
 
-    pCertContext = CertFindCertificateInStore(hStore,
+    pCertContext = pCertFindCertificateInStore(hStore,
                                              ENCODING,
                                              0,
                                              CERT_FIND_SUBJECT_CERT,
@@ -583,10 +682,10 @@ PCCERT_CONTEXT GetCertCtx(CHAR * filename)
          CertFreeCertificateContext(pCertContext);*/
 
     if (hStore)
-      CertCloseStore(hStore,0);
+      pCertCloseStore(hStore,0);
 
     if (hMsg)
-      CryptMsgClose(hMsg);
+      pCryptMsgClose(hMsg);
 
     return pCertContext;
 }
@@ -599,21 +698,36 @@ BOOL VerifyTrust(CHAR * filename)
     GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
     wchar_t wfilename[260];
     LONG ret;
+    BOOL success = FALSE;
+
+    LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
+    HINSTANCE hWinTrust;
 
     if (filename == NULL ) 
         return FALSE;
 
+    hWinTrust = LoadLibrary("wintrust");
+    if ( !hWinTrust )
+        return FALSE;
+
+    if (((FARPROC) pWinVerifyTrust =
+          GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
+    {
+        FreeLibrary(hWinTrust);
+        return FALSE;
+    }
+
     mbstowcs(wfilename, filename, 260);
 
     fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
-                             0, NULL);
+                                    0, NULL);
     fSubjectFile.lpPath = wfilename;
     fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                                                 FALSE, GetCurrentProcessId());
     fContextWSubject.SubjectType = &subject;
     fContextWSubject.Subject = &fSubjectFile;
 
-    ret = WinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, &fContextWSubject);
+    ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
 
     if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
         CloseHandle( fSubjectFile.hFile );
@@ -621,7 +735,7 @@ BOOL VerifyTrust(CHAR * filename)
         CloseHandle( fContextWSubject.hClientToken );
 
     if (ret == ERROR_SUCCESS) {
-        return TRUE;
+        success = TRUE;
     } else {
         DWORD gle = GetLastError();
         switch (gle) {
@@ -637,27 +751,35 @@ BOOL VerifyTrust(CHAR * filename)
         case TRUST_E_SUBJECT_NOT_TRUSTED:
             afsi_log("VerifyTrust failed: File is not trusted");
             break;
+        case TRUST_E_BAD_DIGEST:
+            afsi_log("VerifyTrust failed: Executable has been modified");
+            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;
+        success = FALSE;
     }
+    FreeLibrary(hWinTrust);
+    return success;
 }
 
 void LogCertCtx(PCCERT_CONTEXT pCtx) {
     DWORD dwData;
     LPTSTR szName = NULL;
 
+    if ( hCrypt32 == NULL )
+        return;
+
     // Get Issuer name size.
-    if (!(dwData = CertGetNameString(pCtx,
-                                    CERT_NAME_SIMPLE_DISPLAY_TYPE,
-                                    CERT_NAME_ISSUER_FLAG,
-                                    NULL,
-                                    NULL,
-                                    0))) {
+    if (!(dwData = pCertGetNameString(pCtx,
+                                     CERT_NAME_SIMPLE_DISPLAY_TYPE,
+                                     CERT_NAME_ISSUER_FLAG,
+                                     NULL,
+                                     NULL,
+                                     0))) {
         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
        goto __exit;
     }
@@ -666,12 +788,12 @@ void LogCertCtx(PCCERT_CONTEXT pCtx) {
     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
 
     // Get Issuer name.
-    if (!(CertGetNameString(pCtx,
-                           CERT_NAME_SIMPLE_DISPLAY_TYPE,
-                           CERT_NAME_ISSUER_FLAG,
-                           NULL,
-                           szName,
-                           dwData))) {
+    if (!(pCertGetNameString(pCtx,
+                            CERT_NAME_SIMPLE_DISPLAY_TYPE,
+                            CERT_NAME_ISSUER_FLAG,
+                            NULL,
+                            szName,
+                            dwData))) {
         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
        goto __exit;
     }
@@ -682,12 +804,12 @@ void LogCertCtx(PCCERT_CONTEXT pCtx) {
     szName = NULL;
 
     // Get Subject name size.
-    if (!(dwData = CertGetNameString(pCtx,
-                                    CERT_NAME_SIMPLE_DISPLAY_TYPE,
-                                    0,
-                                    NULL,
-                                    NULL,
-                                    0))) {
+    if (!(dwData = pCertGetNameString(pCtx,
+                                     CERT_NAME_SIMPLE_DISPLAY_TYPE,
+                                     0,
+                                     NULL,
+                                     NULL,
+                                     0))) {
         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
        goto __exit;
     }
@@ -696,12 +818,12 @@ void LogCertCtx(PCCERT_CONTEXT pCtx) {
     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
 
     // Get subject name.
-    if (!(CertGetNameString(pCtx,
-                           CERT_NAME_SIMPLE_DISPLAY_TYPE,
-                           0,
-                           NULL,
-                           szName,
-                           dwData))) {
+    if (!(pCertGetNameString(pCtx,
+                            CERT_NAME_SIMPLE_DISPLAY_TYPE,
+                            0,
+                            NULL,
+                            szName,
+                            dwData))) {
         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
        goto __exit;
     }
@@ -728,6 +850,18 @@ BOOL AFSModulesVerify(void)
     unsigned int i;
     BOOL success = TRUE;
     PCCERT_CONTEXT pCtxService = NULL;
+    HINSTANCE hPSAPI;
+    DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
+    BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
+    DWORD dummyLen, code;
+    DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
+    DWORD verifyServiceSig = TRUE;
+    HKEY parmKey;
+
+    hPSAPI = LoadLibrary("psapi");
+
+    if ( hPSAPI == NULL )
+        return FALSE;
 
     if (!GetModuleFileName(NULL, filename, sizeof(filename)))
         return FALSE;
@@ -737,9 +871,44 @@ BOOL AFSModulesVerify(void)
 
     afsi_log("%s version %s", filename, afsdVersion);
 
-    trustVerified = VerifyTrust(filename);
+    if (((FARPROC) pGetModuleFileNameExA =
+          GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
+         ((FARPROC) pEnumProcessModules =
+           GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
+    {
+        FreeLibrary(hPSAPI);
+        return FALSE;
+    }
+
+
+    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
+                        AFSREG_CLT_SVC_PARAM_SUBKEY,
+                        0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        dummyLen = sizeof(cacheSize);
+        code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
+                               (BYTE *) &cacheSize, &dummyLen);
+        RegCloseKey (parmKey);
+    }
+
+    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        dummyLen = sizeof(verifyServiceSig);
+        code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
+                                (BYTE *) &verifyServiceSig, &dummyLen);
+        RegCloseKey (parmKey);
+    }
+
+    if (verifyServiceSig && cacheSize < 716800) {
+        trustVerified = VerifyTrust(filename);
+    } else {
+        afsi_log("Signature Verification disabled");
+    }
 
     if (trustVerified) {
+        LoadCrypt32();
+
         // get a certificate context for the signer of afsd_service.
         pCtxService = GetCertCtx(filename);
         if (pCtxService)
@@ -750,7 +919,7 @@ BOOL AFSModulesVerify(void)
     hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                            FALSE, GetCurrentProcessId());
 
-    if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
+    if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
     {
         afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
 
@@ -759,7 +928,7 @@ BOOL AFSModulesVerify(void)
             char szModName[2048];
 
             // Get the full path to the module's file.
-            if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName)))
+            if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
             {
                 lstrcpy(checkName, szModName);
                 strlwr(checkName);
@@ -788,7 +957,7 @@ BOOL AFSModulesVerify(void)
                         else if (pCtxService) {
                             PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
 
-                            if (!pCtx || !CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                            if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                                                   pCtxService->pCertInfo,
                                                                   pCtx->pCertInfo)) {
                                 afsi_log("Certificate mismatch: %s", szModName);
@@ -799,7 +968,7 @@ BOOL AFSModulesVerify(void)
                             }
                             
                             if (pCtx)
-                                CertFreeCertificateContext(pCtx);
+                                pCertFreeCertificateContext(pCtx);
                         }
                     }
                 }
@@ -807,17 +976,17 @@ BOOL AFSModulesVerify(void)
         }
     }
 
-    if (pCtxService)
-        CertFreeCertificateContext(pCtxService);
+    if (pCtxService) {
+        pCertFreeCertificateContext(pCtxService);
+        UnloadCrypt32();
+    }
+
+    FreeLibrary(hPSAPI);
 
     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.
 */
@@ -828,16 +997,16 @@ typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc   )(  LPCTSTR ,
 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
 RegisterServiceCtrlHandlerFunc   pRegisterServiceCtrlHandler   = NULL; 
 
-void afsd_Main(DWORD argc, LPTSTR *argv)
+VOID WINAPI
+afsd_Main(DWORD argc, LPTSTR *argv)
 {
     long code;
     char *reason;
 #ifdef JUMP
     int jmpret;
 #endif /* JUMP */
-    HANDLE hInitHookDll;
-    HANDLE hAdvApi32;
-    AfsdInitHook initHook;
+    HMODULE hHookDll;
+    HMODULE hAdvApi32;
 
 #ifdef _DEBUG
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
@@ -881,7 +1050,7 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
     ServiceStatus.dwCheckPoint = 1;
     ServiceStatus.dwWaitHint = 30000;
     /* accept Power Events */
-    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
+    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
     SetServiceStatus(StatusHandle, &ServiceStatus);
 #endif
 
@@ -901,7 +1070,8 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
         int bpower = TRUE;
 
         /* see if we should handle power notifications */
-        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &hkParm);
+        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 
+                            0, KEY_QUERY_VALUE, &hkParm);
         if (code == ERROR_SUCCESS) {
             dummyLen = sizeof(bpower);
             code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
@@ -934,17 +1104,17 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
     }
 
     /* allow an exit to be called prior to any initialization */
-    hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
-    if (hInitHookDll)
+    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    if (hHookDll)
     {
         BOOL hookRc = FALSE;
-        initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
+        AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
         if (initHook)
         {
             hookRc = initHook();
         }
-        FreeLibrary(hInitHookDll);
-        hInitHookDll = NULL;
+        FreeLibrary(hHookDll);
+        hHookDll = NULL;
 
         if (hookRc == FALSE)
         {
@@ -968,7 +1138,7 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
             ServiceStatus.dwCheckPoint = 2;
             ServiceStatus.dwWaitHint = 20000;
             /* accept Power Events */
-            ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
+            ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
             SetServiceStatus(StatusHandle, &ServiceStatus);
         }
     }
@@ -997,6 +1167,33 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
                        osi_panic(reason, __FILE__, __LINE__);
         }
 
+        /* allow an exit to be called post rx initialization */
+        hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+        if (hHookDll)
+        {
+            BOOL hookRc = FALSE;
+            AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
+            if (rxStartedHook)
+            {
+                hookRc = rxStartedHook();
+            }
+            FreeLibrary(hHookDll);
+            hHookDll = 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;
+            }
+        }
+
 #ifndef NOTSERVICE
         ServiceStatus.dwCheckPoint++;
         ServiceStatus.dwWaitHint -= 5000;
@@ -1008,6 +1205,33 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
             osi_panic(reason, __FILE__, __LINE__);
         }
 
+        /* allow an exit to be called post smb initialization */
+        hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+        if (hHookDll)
+        {
+            BOOL hookRc = FALSE;
+            AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
+            if (smbStartedHook)
+            {
+                hookRc = smbStartedHook();
+            }
+            FreeLibrary(hHookDll);
+            hHookDll = 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;
+            }
+        }
+
         MountGlobalDrives();
 
 #ifndef NOTSERVICE
@@ -1017,7 +1241,7 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
         ServiceStatus.dwWaitHint = 0;
 
         /* accept Power events */
-        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
+        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
         SetServiceStatus(StatusHandle, &ServiceStatus);
 #endif  
         {
@@ -1031,6 +1255,8 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
 
     WaitForSingleObject(WaitToTerminate, INFINITE);
 
+    afsi_log("Received Termination Signal, Stopping Service");
+
     {   
         HANDLE h; char *ptbuf[1];
        h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
@@ -1040,9 +1266,57 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
         DeregisterEventSource(h);
     }
 
+    /* allow an exit to be called prior to stopping the service */
+    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    if (hHookDll)
+    {
+        BOOL hookRc = FALSE;
+        AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
+        if (stoppingHook)
+        {
+            hookRc = stoppingHook();
+        }
+        FreeLibrary(hHookDll);
+        hHookDll = 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;
+        }
+    }
+
+
+#ifdef AFS_FREELANCE_CLIENT
+    cm_FreelanceShutdown();
+    afsi_log("Freelance Shutdown complete");
+#endif
+
     DismountGlobalDrives();
-    smb_Shutdown();
-    rx_Finalize();
+    afsi_log("Global Drives dismounted");
+                                         
+    cm_DaemonShutdown();                 
+    afsi_log("Daemon shutdown complete");
+                                         
+    buf_Shutdown();                      
+    afsi_log("Buffer shutdown complete");
+                                         
+    rx_Finalize();                       
+    afsi_log("rx finalization complete");
+                                         
+    smb_Shutdown();                      
+    afsi_log("smb shutdown complete");   
+                                         
+    RpcShutdown();                       
+
+    cm_ShutdownMappedMemory();           
 
 #ifdef REGISTER_POWER_NOTIFICATIONS
     /* terminate thread used to flush cache */
@@ -1050,6 +1324,20 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
         PowerNotificationThreadExit();
 #endif
 
+    /* allow an exit to be called after stopping the service */
+    hHookDll = LoadLibrary(AFSD_HOOK_DLL);
+    if (hHookDll)
+    {
+        BOOL hookRc = FALSE;
+        AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
+        if (stoppedHook)
+        {
+            hookRc = stoppedHook();
+        }
+        FreeLibrary(hHookDll);
+        hHookDll = NULL;
+    }
+
     /* Remove the ExceptionFilter */
     SetUnhandledExceptionFilter(NULL);
 
@@ -1068,13 +1356,33 @@ DWORD __stdcall afsdMain_thread(void* notUsed)
     return(0);
 }
 
+void usage(void)
+{
+    fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
+}
+
 int
-main(void)
+main(int argc, char * argv[])
 {
     static SERVICE_TABLE_ENTRY dispatchTable[] = {
         {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
         {NULL, NULL}
     };
+    int i;
+
+    for (i = 1; i < argc; i++) {
+        if (!stricmp(argv[i],"--validate-cache")) {
+            if (++i != argc - 1) {
+                usage();
+                return(1);
+            }
+
+            return cm_ValidateMappedMemory(argv[i]);
+        } else {
+            usage();
+            return(1);
+        }
+    }
 
     if (!StartServiceCtrlDispatcher(dispatchTable))
     {