2b7298a9aa1a41862f7740b2eb4bd1eb107e1d33
[openafs.git] / src / WINNT / afsd / afsd_service.c
1
2 #include <afs/stds.h>
3
4 #include <windows.h>
5 #include <softpub.h>
6 #include <psapi.h>
7 #include <winerror.h>
8 #include <string.h>
9 #include <setjmp.h>
10 #include "afsd.h"
11 #include "afsd_init.h"
12 #include "lanahelper.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <winsock2.h>
16 #include <WINNT\afsreg.h>
17 #include "cm_btree.h"
18 #include "cm_rpc.h"
19 #include "smb.h"
20
21 #include <osi.h>
22
23 #ifdef DEBUG
24 //#define NOTSERVICE
25 #endif
26 #ifdef _DEBUG
27 #include <crtdbg.h>
28 #endif
29
30 //#define REGISTER_POWER_NOTIFICATIONS 1
31 #include "afsd_flushvol.h"
32
33 extern void afsi_log(char *pattern, ...);
34
35 static SERVICE_STATUS           ServiceStatus;
36 static SERVICE_STATUS_HANDLE    StatusHandle;
37 static BOOL bRunningAsService = TRUE;
38
39 HANDLE hAFSDMainThread = NULL;
40
41 HANDLE WaitToTerminate;
42
43 static int GlobalStatus;
44
45 #ifdef JUMP
46 unsigned int MainThreadId;
47 jmp_buf notifier_jmp;
48 #endif /* JUMP */
49
50 extern int traceOnPanic;
51 extern HANDLE afsi_file;
52
53 static int powerEventsRegistered = 0;
54 extern int powerStateSuspended = 0;
55
56 static VOID (WINAPI* pRtlCaptureContext)(PCONTEXT ContextRecord) = NULL;
57
58 /*
59  * Notifier function for use by osi_panic
60  */
61 static void afsd_notifier(char *msgp, char *filep, long line)
62 {
63     CONTEXT context;
64
65     if (!msgp)
66         msgp = "unspecified assert";
67
68     if (filep)
69         LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION, 
70                  filep, line, msgp);
71     else
72         LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG, msgp);
73
74     GlobalStatus = line;
75
76     osi_LogEnable(afsd_logp);
77
78     afsd_ForceTrace(TRUE);
79     buf_ForceTrace(TRUE);
80
81     if (pRtlCaptureContext) {
82         pRtlCaptureContext(&context);
83         afsd_printStack(GetCurrentThread(), &context);
84     }
85
86     afsi_log("--- begin dump ---");
87     cm_MemDumpDirStats(afsi_file, "a", 0);
88     cm_MemDumpBPlusStats(afsi_file, "a", 0);
89     cm_DumpCells(afsi_file, "a", 0);
90     cm_DumpVolumes(afsi_file, "a", 0);
91     cm_DumpSCache(afsi_file, "a", 0);
92     cm_DumpBufHashTable(afsi_file, "a", 0);
93     cm_DumpServers(afsi_file, "a", 0);
94     smb_DumpVCP(afsi_file, "a", 0);                     
95     rx_DumpPackets(afsi_file, "a");
96     rx_DumpCalls(afsi_file, "a");
97     afsi_log("--- end   dump ---");
98     
99 #ifdef DEBUG
100     if (IsDebuggerPresent())
101         DebugBreak();   
102 #endif
103
104     GenerateMiniDump(NULL);
105
106     SetEvent(WaitToTerminate);
107
108 #ifdef JUMP
109     if (GetCurrentThreadId() == MainThreadId)
110         longjmp(notifier_jmp, 1);
111 #endif /* JUMP */
112
113     if (bRunningAsService) {
114         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
115         ServiceStatus.dwWin32ExitCode = NO_ERROR;
116         ServiceStatus.dwCheckPoint = 0;
117         ServiceStatus.dwWaitHint = 0;
118         ServiceStatus.dwControlsAccepted = 0;
119         SetServiceStatus(StatusHandle, &ServiceStatus);
120     }
121     exit(1);
122 }
123
124 /*
125  * For use miscellaneously in smb.c; need to do better
126  */
127 static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
128 {
129     return 0;
130 }
131
132 DWORD
133 afsd_ServiceFlushVolume(DWORD dwlpEventData)
134 {
135     DWORD   dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
136
137     /*
138     **  If UI bit is not set, user interaction is not possible
139     **      BUT, since we are a NON-interactive service, and therefore
140     **  have NO user I/O, it doesn't much matter.
141     **  This benign code left here as example of how to find this out
142     */
143     BOOL bUI = (dwlpEventData & 1);
144
145     /* flush volume */
146     if ( PowerNotificationThreadNotify() )
147     {
148         dwRet = NO_ERROR;
149     }
150     else
151     {
152         /* flush was unsuccessful, or timeout - deny shutdown */
153         dwRet = ERROR_NETWORK_BUSY;
154     }
155
156     /*      to deny hibernate, simply return
157     //      any value besides NO_ERROR.
158     //      For example:
159     //      dwRet = ERROR_NETWORK_BUSY;
160     */
161
162     return dwRet;
163 }
164
165
166 /* service control handler used in nt4 only for backward compat. */
167 VOID WINAPI 
168 afsd_ServiceControlHandler(DWORD ctrlCode)
169 {
170     HKEY parmKey;
171     DWORD dummyLen, doTrace;
172     long code;
173
174     switch (ctrlCode) {
175     case SERVICE_CONTROL_SHUTDOWN:
176     case SERVICE_CONTROL_STOP:
177         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
178         ServiceStatus.dwWin32ExitCode = NO_ERROR;
179         ServiceStatus.dwCheckPoint = 1;
180         ServiceStatus.dwWaitHint = 30000;
181         ServiceStatus.dwControlsAccepted = 0;
182         SetServiceStatus(StatusHandle, &ServiceStatus);
183
184         if (ctrlCode == SERVICE_CONTROL_STOP)
185             afsi_log("SERVICE_CONTROL_STOP");
186         else
187             afsi_log("SERVICE_CONTROL_SHUTDOWN");
188
189         /* Write all dirty buffers back to server */
190         if ( !lana_OnlyLoopback() )
191             buf_CleanAndReset();
192
193         /* Force trace if requested */
194         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
195                              AFSREG_CLT_SVC_PARAM_SUBKEY,
196                              0, KEY_QUERY_VALUE, &parmKey);
197         if (code != ERROR_SUCCESS)
198             goto doneTrace;
199
200         dummyLen = sizeof(doTrace);
201         code = RegQueryValueEx(parmKey, "TraceOnShutdown",
202                                 NULL, NULL,
203                                 (BYTE *) &doTrace, &dummyLen);
204         RegCloseKey (parmKey);
205         if (code != ERROR_SUCCESS)
206             doTrace = 0;
207         if (doTrace) {
208             afsd_ForceTrace(FALSE);
209             buf_ForceTrace(FALSE);
210         }
211
212       doneTrace:
213         SetEvent(WaitToTerminate);
214         break;
215
216     case SERVICE_CONTROL_INTERROGATE:
217         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
218         ServiceStatus.dwWin32ExitCode = NO_ERROR;
219         ServiceStatus.dwCheckPoint = 0;
220         ServiceStatus.dwWaitHint = 0;
221         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
222         SetServiceStatus(StatusHandle, &ServiceStatus);
223         break;
224         /* XXX handle system shutdown */
225         /* XXX handle pause & continue */
226     }
227 }       
228
229
230 /*
231 **    Extended ServiceControlHandler that provides Event types
232 **    for monitoring Power events, for example.
233 */
234 DWORD WINAPI
235 afsd_ServiceControlHandlerEx(
236               DWORD  ctrlCode,
237               DWORD  dwEventType,
238               LPVOID lpEventData,
239               LPVOID lpContext
240               )
241 {
242     HKEY parmKey;
243     DWORD dummyLen, doTrace;
244     long code;
245     DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
246     OSVERSIONINFO osVersion;
247
248     /* Get the version of Windows */
249     memset(&osVersion, 0x00, sizeof(osVersion));
250     osVersion.dwOSVersionInfoSize = sizeof(osVersion);
251     GetVersionEx(&osVersion);
252
253     switch (ctrlCode) 
254     {
255     case SERVICE_CONTROL_SHUTDOWN:
256     case SERVICE_CONTROL_STOP:
257         if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
258             afsi_log("SERVICE_CONTROL_SHUTDOWN");
259         else
260             afsi_log("SERVICE_CONTROL_STOP");
261
262         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
263         ServiceStatus.dwWin32ExitCode = NO_ERROR;
264         ServiceStatus.dwCheckPoint = 1;
265         ServiceStatus.dwWaitHint = 30000;
266         ServiceStatus.dwControlsAccepted = 0;
267         SetServiceStatus(StatusHandle, &ServiceStatus);
268
269         /* Write all dirty buffers back to server */
270         if ( !lana_OnlyLoopback() )
271             buf_CleanAndReset();
272
273         /* Force trace if requested */
274         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
275                             AFSREG_CLT_SVC_PARAM_SUBKEY,
276                             0, KEY_QUERY_VALUE, &parmKey);
277         if (code != ERROR_SUCCESS)
278             goto doneTrace;
279
280         dummyLen = sizeof(doTrace);
281         code = RegQueryValueEx(parmKey, "TraceOnShutdown",
282                                NULL, NULL,
283                                (BYTE *) &doTrace, &dummyLen);
284         RegCloseKey (parmKey);
285         if (code != ERROR_SUCCESS)
286             doTrace = 0;
287         if (doTrace) {
288             afsd_ForceTrace(FALSE);
289             buf_ForceTrace(FALSE);
290         }
291
292       doneTrace:
293         SetEvent(WaitToTerminate);
294         dwRet = NO_ERROR;
295         break;
296
297     case SERVICE_CONTROL_INTERROGATE:
298         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
299         ServiceStatus.dwWin32ExitCode = NO_ERROR;
300         ServiceStatus.dwCheckPoint = 0;
301         ServiceStatus.dwWaitHint = 0;
302         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT;
303         SetServiceStatus(StatusHandle, &ServiceStatus);
304         afsi_log("SERVICE_CONTROL_INTERROGATE");
305         dwRet = NO_ERROR;
306         break;
307
308         /* XXX handle system shutdown */
309         /* XXX handle pause & continue */
310     case SERVICE_CONTROL_POWEREVENT:                                              
311         { 
312 #ifdef DEBUG
313             afsi_log("SERVICE_CONTROL_POWEREVENT");
314 #endif
315             /*                                                                                
316             **  dwEventType of this notification == WPARAM of WM_POWERBROADCAST               
317             **  Return NO_ERROR == return TRUE for that message, i.e. accept request          
318             **  Return any error code to deny request,                                        
319             **  i.e. as if returning BROADCAST_QUERY_DENY                                     
320             */                                                                                
321             if (powerEventsRegistered) {
322                 switch((int) dwEventType)                                                         
323                 {                                                                               
324                 case PBT_APMQUERYSUSPEND:       
325                     afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND"); 
326                     /* Write all dirty buffers back to server */
327                     if ( !lana_OnlyLoopback() ) {
328                         buf_CleanAndReset();
329                         cm_SuspendSCache();
330                     }
331                     afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete"); 
332                     dwRet = NO_ERROR;                       
333                     break;                                  
334                 case PBT_APMQUERYSTANDBY:                                                         
335                     afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY"); 
336                     /* Write all dirty buffers back to server */
337                     if ( !lana_OnlyLoopback() ) {
338                         buf_CleanAndReset();
339                         cm_SuspendSCache();
340                     }
341                     afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete"); 
342                     dwRet = NO_ERROR;                                                             
343                     break;                                                                        
344                                                                                                                           
345                     /* allow remaining case PBT_WhatEver */                                           
346                 case PBT_APMSUSPEND:                         
347                     afsi_log("SERVICE_CONTROL_APMSUSPEND");
348                     powerStateSuspended = 1;
349                     if (osVersion.dwMajorVersion >= 6) {
350                         cm_SuspendSCache();
351                         smb_StopListeners(0);
352                     }
353                     dwRet = NO_ERROR;                       
354                     break;                                  
355                 case PBT_APMSTANDBY:                  
356                     afsi_log("SERVICE_CONTROL_APMSTANDBY"); 
357                     powerStateSuspended = 1;
358                     if (osVersion.dwMajorVersion >= 6) {
359                         cm_SuspendSCache();
360                         smb_StopListeners(0);
361                     }
362                     dwRet = NO_ERROR;                       
363                     break;                                  
364                 case PBT_APMRESUMECRITICAL:             
365                     afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL"); 
366                     if (osVersion.dwMajorVersion >= 6)
367                         smb_RestartListeners(0);
368                     dwRet = NO_ERROR;                       
369                     break;                                  
370                 case PBT_APMRESUMESUSPEND:                                                        
371                     /* User logged in after suspend */
372                     afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND"); 
373                     dwRet = NO_ERROR;                       
374                     break;                                  
375                 case PBT_APMRESUMESTANDBY:            
376                     /* User logged in after standby */
377                     afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY"); 
378                     dwRet = NO_ERROR;                       
379                     break;                                  
380                 case PBT_APMBATTERYLOW:                                                           
381                     afsi_log("SERVICE_CONTROL_APMBATTERYLOW"); 
382                     dwRet = NO_ERROR;                       
383                     break;                                  
384                 case PBT_APMPOWERSTATUSCHANGE:                                                    
385 #ifdef DEBUG
386                     afsi_log("SERVICE_CONTROL_APMPOWERSTATUSCHANGE");
387 #endif
388                     dwRet = NO_ERROR;                       
389                     break;                                  
390                 case PBT_APMOEMEVENT:                                                             
391 #ifdef DEBUG
392                     afsi_log("SERVICE_CONTROL_APMOEMEVENT"); 
393 #endif
394                     dwRet = NO_ERROR;                       
395                     break;                                  
396                 case PBT_APMRESUMEAUTOMATIC:          
397                     /* This is the message delivered once all devices are up */
398                     afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC"); 
399                     powerStateSuspended = 0;
400                     if (osVersion.dwMajorVersion >= 6) {
401                         smb_SetLanAdapterChangeDetected();
402                     }
403                     dwRet = NO_ERROR;                       
404                     break;                                  
405                 default:                                                                          
406                     afsi_log("SERVICE_CONTROL_unknown"); 
407                     dwRet = NO_ERROR;                       
408                 }   
409             }
410         }
411         break;
412     case SERVICE_CONTROL_CUSTOM_DUMP: 
413         {
414             afsi_log("SERVICE_CONTROL_CUSTOM_DUMP"); 
415             GenerateMiniDump(NULL);
416             dwRet = NO_ERROR;
417         }
418         break;
419     }           /* end switch(ctrlCode) */                                                        
420     return dwRet;   
421 }
422
423 /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
424  * 
425  * Mount a drive into AFS if there global mapping
426  */
427 /* DEE Could check first if we are run as SYSTEM */
428 #define MAX_RETRIES 10
429 #define MAX_DRIVES  23
430 static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
431 {
432     char szAfsPath[_MAX_PATH];
433     char szDriveToMapTo[5];
434     DWORD dwResult;
435     char szKeyName[256];
436     HKEY hKey;
437     DWORD dwIndex = 0, dwRetry = 0;
438     DWORD dwDriveSize;
439     DWORD dwSubMountSize;
440     char szSubMount[256];
441     DWORD dwType;
442
443     sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
444
445     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
446     if (dwResult != ERROR_SUCCESS)
447         return 0;
448
449     while (dwIndex < MAX_DRIVES) {
450         dwDriveSize = sizeof(szDriveToMapTo);
451         dwSubMountSize = sizeof(szSubMount);
452         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
453         if (dwResult != ERROR_MORE_DATA) {
454             if (dwResult != ERROR_SUCCESS) {
455                 if (dwResult != ERROR_NO_MORE_ITEMS)
456                     afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
457                 break;
458             }
459         }
460
461         for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
462         {
463             NETRESOURCE nr;
464             memset (&nr, 0x00, sizeof(NETRESOURCE));
465
466             sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
467
468             nr.dwScope = RESOURCE_GLOBALNET;              /* ignored parameter */
469             nr.dwType=RESOURCETYPE_DISK;
470             nr.lpLocalName=strlen(szDriveToMapTo) > 0 ? szDriveToMapTo : NULL;
471             nr.lpRemoteName=szAfsPath;
472             nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; /* ignored parameter */
473             nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;       /* ignored parameter */
474
475             dwResult = WNetAddConnection2(&nr,NULL,NULL,0);
476             afsi_log("GlobalAutoMap of %s to %s %s (%d)", szDriveToMapTo, szSubMount, 
477                      (dwResult == NO_ERROR) ? "succeeded" : "failed", dwResult);
478             if (dwResult == NO_ERROR) {
479                 break;
480             }
481             /* wait for smb server to come up */
482             Sleep((DWORD)1000 /* miliseconds */);               
483
484             /* Disconnect any previous mappings */
485             dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
486         }
487     }        
488
489     RegCloseKey(hKey);
490     return 0;
491 }
492
493 static HANDLE hThreadMountGlobalDrives = NULL;
494
495 static void MountGlobalDrives()
496 {
497     DWORD tid;
498
499     hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
500
501     if ( hThreadMountGlobalDrives ) {
502         DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
503         if (rc == WAIT_TIMEOUT) {
504             afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
505         } else if (rc == WAIT_OBJECT_0) {
506             afsi_log("GlobalAutoMap thread completed");
507             CloseHandle( hThreadMountGlobalDrives );
508             hThreadMountGlobalDrives = NULL;
509         }
510     }
511 }
512
513 static void DismountGlobalDrives()
514 {
515     char szAfsPath[_MAX_PATH];
516     char szDriveToMapTo[5];
517     DWORD dwDriveSize;
518     DWORD dwSubMountSize;
519     char szSubMount[256];
520     DWORD dwType;
521     DWORD dwResult;
522     char szKeyName[256];
523     HKEY hKey;
524     DWORD dwIndex = 0;
525
526     if ( hThreadMountGlobalDrives ) {
527         DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
528
529         if (rc == WAIT_TIMEOUT) {
530             afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
531         }
532         else if (rc == WAIT_OBJECT_0) {
533             afsi_log("GlobalAutoMap thread completed");
534             CloseHandle( hThreadMountGlobalDrives );
535             hThreadMountGlobalDrives = NULL;
536         }
537     }
538
539     sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
540
541     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
542     if (dwResult != ERROR_SUCCESS)
543         return;
544
545     while (dwIndex < MAX_DRIVES) {
546         dwDriveSize = sizeof(szDriveToMapTo);
547         dwSubMountSize = sizeof(szSubMount);
548         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
549         if (dwResult != ERROR_MORE_DATA) {
550             if (dwResult != ERROR_SUCCESS) {
551                 if (dwResult != ERROR_NO_MORE_ITEMS)
552                     afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
553                 break;
554             }
555         }
556
557         sprintf(szAfsPath,"\\\\%s\\%s",cm_NetbiosName,szSubMount);
558                     
559         dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
560         dwResult = WNetCancelConnection(szAfsPath, TRUE);
561         
562         afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
563     }        
564
565     RegCloseKey(hKey);
566 }
567
568 DWORD
569 GetVersionInfo( CHAR * filename, CHAR * szOutput, DWORD dwOutput )
570 {
571     DWORD dwVersionHandle;
572     LPVOID pVersionInfo = 0;
573     DWORD retval = 0;
574     LPDWORD pLangInfo = 0;
575     LPTSTR szVersion = 0;
576     UINT len = 0;
577     TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
578     DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
579
580     if (!size) {
581         afsi_log("GetFileVersionInfoSize failed");
582         return GetLastError();
583     }
584
585     pVersionInfo = malloc(size);
586     if (!pVersionInfo) {
587         afsi_log("out of memory 1");
588         return ERROR_NOT_ENOUGH_MEMORY;
589     }
590
591     GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
592     if (retval = GetLastError())
593     {
594         afsi_log("GetFileVersionInfo failed: %d", retval);
595         goto cleanup;
596     }
597
598     VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
599                        (LPVOID*)&pLangInfo, &len);
600     if (retval = GetLastError())
601     {
602         afsi_log("VerQueryValue 1 failed: %d", retval);
603         goto cleanup;
604     }
605
606     wsprintf(szVerQ,
607              TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
608              LOWORD(*pLangInfo), HIWORD(*pLangInfo));
609
610     VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
611     if (retval = GetLastError())
612     {
613         /* try again with language 409 since the old binaries were tagged wrong */
614         wsprintf(szVerQ,
615                   TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
616                   HIWORD(*pLangInfo));
617
618         VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
619         if (retval = GetLastError()) {
620             afsi_log("VerQueryValue 2 failed: [%s] %d", szVerQ, retval);
621             goto cleanup;
622         }
623     }
624     snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
625     szOutput[dwOutput - 1] = 0;
626
627  cleanup:
628     if (pVersionInfo)
629         free(pVersionInfo);
630
631     return retval;
632 }
633
634 static HINSTANCE hCrypt32;
635 static DWORD (WINAPI *pCertGetNameString)(PCCERT_CONTEXT pCertContext,  DWORD dwType,  DWORD dwFlags,
636                                           void* pvTypePara, LPTSTR pszNameString, DWORD cchNameString);
637 static BOOL (WINAPI *pCryptQueryObject)(DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags,
638                                         DWORD dwExpectedFormatTypeFlags, DWORD dwFlags,
639                                         DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType,
640                                         DWORD* pdwFormatType, HCERTSTORE* phCertStore,
641                                         HCRYPTMSG* phMsg, const void** ppvContext);
642 static BOOL (WINAPI *pCryptMsgGetParam)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex,
643                                         void* pvData, DWORD* pcbData);
644 static PCCERT_CONTEXT (WINAPI *pCertFindCertificateInStore)(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
645                                                             DWORD dwFindFlags, DWORD dwFindType,
646                                                             const void* pvFindPara,
647                                                             PCCERT_CONTEXT pPrevCertContext);
648 static BOOL (WINAPI *pCertCloseStore)(HCERTSTORE hCertStore, DWORD dwFlags);
649 static BOOL (WINAPI *pCryptMsgClose)(HCRYPTMSG hCryptMsg);
650 static BOOL (WINAPI *pCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1,
651                                               PCERT_INFO pCertId2);
652 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
653
654 void LoadCrypt32(void)
655 {
656     hCrypt32 = LoadLibrary("crypt32");
657     if ( !hCrypt32 )
658         return;
659
660     (FARPROC) pCertGetNameString = GetProcAddress( hCrypt32, "CertGetNameString" );
661     (FARPROC) pCryptQueryObject = GetProcAddress( hCrypt32, "CryptQueryObject" );
662     (FARPROC) pCryptMsgGetParam = GetProcAddress( hCrypt32, "CryptMsgGetParam" );
663     (FARPROC) pCertFindCertificateInStore = GetProcAddress( hCrypt32, "CertFindCertificateInStore" );
664     (FARPROC) pCertCloseStore = GetProcAddress( hCrypt32, "CertCloseStore" );
665     (FARPROC) pCryptMsgClose = GetProcAddress( hCrypt32, "CryptMsgClose" );
666     (FARPROC) pCertCompareCertificate = GetProcAddress( hCrypt32, "CertCompareCertificate" );
667     (FARPROC) pCertFreeCertificateContext = GetProcAddress( hCrypt32, "CertFreeCertificateContext" );
668     
669     if ( !pCertGetNameString ||
670          !pCryptQueryObject ||
671          !pCryptMsgGetParam ||
672          !pCertFindCertificateInStore ||
673          !pCertCloseStore ||
674          !pCryptMsgClose ||
675          !pCertCompareCertificate ||
676          !pCertFreeCertificateContext)
677     {
678         FreeLibrary(hCrypt32);
679         hCrypt32 = NULL;
680     }
681 }
682
683 void UnloadCrypt32(void)
684 {
685     FreeLibrary(hCrypt32);
686 }
687
688 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
689
690 PCCERT_CONTEXT GetCertCtx(CHAR * filename)
691 {
692     wchar_t wfilename[260];
693     BOOL fResult;
694     DWORD dwEncoding;
695     DWORD dwContentType;
696     DWORD dwFormatType;
697     DWORD dwSignerInfo;
698     HCERTSTORE hStore = NULL;
699     HCRYPTMSG hMsg = NULL;
700     PCMSG_SIGNER_INFO pSignerInfo = NULL;
701     PCCERT_CONTEXT pCertContext = NULL;
702     CERT_INFO CertInfo;
703
704     if ( hCrypt32 == NULL )
705         return NULL;
706
707     ZeroMemory(&CertInfo, sizeof(CertInfo));
708     mbstowcs(wfilename, filename, 260);
709
710     fResult = pCryptQueryObject(CERT_QUERY_OBJECT_FILE,
711                                 wfilename,
712                                 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
713                                 CERT_QUERY_FORMAT_FLAG_BINARY,
714                                 0,
715                                 &dwEncoding,
716                                 &dwContentType,
717                                 &dwFormatType,
718                                 &hStore,
719                                 &hMsg,
720                                 NULL);
721
722     if (!fResult) {
723         afsi_log("CryptQueryObject failed for [%s] with error 0x%x",
724                  filename,
725                  GetLastError());
726         goto __exit;
727     }
728
729     fResult = pCryptMsgGetParam(hMsg,
730                                 CMSG_SIGNER_INFO_PARAM,
731                                 0,
732                                 NULL,
733                                 &dwSignerInfo);
734
735     if (!fResult) {
736         afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
737                  filename,
738                  GetLastError());
739         goto __exit;
740     }
741
742     pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
743
744     fResult = pCryptMsgGetParam(hMsg,
745                                 CMSG_SIGNER_INFO_PARAM,
746                                 0,
747                                 (PVOID)pSignerInfo,
748                                 &dwSignerInfo);
749     
750     if (!fResult) {
751         afsi_log("CryptMsgGetParam failed for [%s] with error 0x%x",
752                  filename,
753                  GetLastError());
754         goto __exit;
755     }
756
757     CertInfo.Issuer = pSignerInfo->Issuer;
758     CertInfo.SerialNumber = pSignerInfo->SerialNumber;
759
760     pCertContext = pCertFindCertificateInStore(hStore,
761                                               ENCODING,
762                                               0,
763                                               CERT_FIND_SUBJECT_CERT,
764                                               (PVOID) &CertInfo,
765                                               NULL);
766
767     if (!pCertContext) {
768       afsi_log("CertFindCertificateInStore for file [%s] failed with 0x%x",
769                filename,
770                GetLastError());
771       goto __exit;
772     }
773
774   __exit:
775     if (pSignerInfo)
776       LocalFree(pSignerInfo);
777
778     /*    if (pCertContext)
779           CertFreeCertificateContext(pCertContext);*/
780
781     if (hStore)
782       pCertCloseStore(hStore,0);
783
784     if (hMsg)
785       pCryptMsgClose(hMsg);
786
787     return pCertContext;
788 }
789
790 BOOL VerifyTrust(CHAR * filename)
791 {
792     WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT fContextWSubject;
793     WIN_TRUST_SUBJECT_FILE fSubjectFile;
794     GUID trustAction = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
795     GUID subject = WIN_TRUST_SUBJTYPE_PE_IMAGE;
796     wchar_t wfilename[260];
797     LONG ret;
798     BOOL success = FALSE;
799
800     LONG (WINAPI *pWinVerifyTrust)(HWND hWnd, GUID* pgActionID, WINTRUST_DATA* pWinTrustData) = NULL;
801     HINSTANCE hWinTrust;
802
803     if (filename == NULL ) 
804         return FALSE;
805
806     hWinTrust = LoadLibrary("wintrust");
807     if ( !hWinTrust )
808         return FALSE;
809
810     if (((FARPROC) pWinVerifyTrust =
811           GetProcAddress( hWinTrust, "WinVerifyTrust" )) == NULL )
812     {
813         FreeLibrary(hWinTrust);
814         return FALSE;
815     }
816
817     mbstowcs(wfilename, filename, 260);
818
819     fSubjectFile.hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
820                                     0, NULL);
821     fSubjectFile.lpPath = wfilename;
822     fContextWSubject.hClientToken = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
823                                                 FALSE, GetCurrentProcessId());
824     fContextWSubject.SubjectType = &subject;
825     fContextWSubject.Subject = &fSubjectFile;
826
827     ret = pWinVerifyTrust(INVALID_HANDLE_VALUE, &trustAction, (WINTRUST_DATA *)&fContextWSubject);
828
829     if ( fSubjectFile.hFile != INVALID_HANDLE_VALUE )
830         CloseHandle( fSubjectFile.hFile );
831     if ( fContextWSubject.hClientToken != INVALID_HANDLE_VALUE )
832         CloseHandle( fContextWSubject.hClientToken );
833
834     if (ret == ERROR_SUCCESS) {
835         success = TRUE;
836     } else {
837         DWORD gle = GetLastError();
838         switch (gle) {
839         case TRUST_E_PROVIDER_UNKNOWN:
840             afsi_log("VerifyTrust failed: \"Generic Verify V2\" Provider Unknown");
841             break;  
842         case TRUST_E_NOSIGNATURE:
843             afsi_log("VerifyTrust failed: Unsigned executable");
844             break;
845         case TRUST_E_EXPLICIT_DISTRUST:
846             afsi_log("VerifyTrust failed: Certificate Marked as Untrusted by the user");
847             break;
848         case TRUST_E_SUBJECT_NOT_TRUSTED:
849             afsi_log("VerifyTrust failed: File is not trusted");
850             break;
851         case TRUST_E_BAD_DIGEST:
852             afsi_log("VerifyTrust failed: Executable has been modified");
853             break;
854         case CRYPT_E_SECURITY_SETTINGS:
855             afsi_log("VerifyTrust failed: local security options prevent verification");
856             break;
857         default:
858             afsi_log("VerifyTrust failed: 0x%X", GetLastError());
859         }
860         success = FALSE;
861     }
862     FreeLibrary(hWinTrust);
863     return success;
864 }
865
866 void LogCertCtx(PCCERT_CONTEXT pCtx) {
867     DWORD dwData;
868     LPTSTR szName = NULL;
869
870     if ( hCrypt32 == NULL )
871         return;
872
873     // Get Issuer name size.
874     if (!(dwData = pCertGetNameString(pCtx,
875                                       CERT_NAME_SIMPLE_DISPLAY_TYPE,
876                                       CERT_NAME_ISSUER_FLAG,
877                                       NULL,
878                                       NULL,
879                                       0))) {
880         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
881         goto __exit;
882     }
883
884     // Allocate memory for Issuer name.
885     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
886
887     // Get Issuer name.
888     if (!(pCertGetNameString(pCtx,
889                              CERT_NAME_SIMPLE_DISPLAY_TYPE,
890                              CERT_NAME_ISSUER_FLAG,
891                              NULL,
892                              szName,
893                              dwData))) {
894         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
895         goto __exit;
896     }
897
898     // print Issuer name.
899     afsi_log("Issuer Name: %s", szName);
900     LocalFree(szName);
901     szName = NULL;
902
903     // Get Subject name size.
904     if (!(dwData = pCertGetNameString(pCtx,
905                                       CERT_NAME_SIMPLE_DISPLAY_TYPE,
906                                       0,
907                                       NULL,
908                                       NULL,
909                                       0))) {
910         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
911         goto __exit;
912     }
913
914     // Allocate memory for subject name.
915     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
916
917     // Get subject name.
918     if (!(pCertGetNameString(pCtx,
919                              CERT_NAME_SIMPLE_DISPLAY_TYPE,
920                              0,
921                              NULL,
922                              szName,
923                              dwData))) {
924         afsi_log("CertGetNameString failed: 0x%x", GetLastError());
925         goto __exit;
926     }
927
928     // Print Subject Name.
929     afsi_log("Subject Name: %s", szName);
930
931   __exit:
932
933     if (szName)
934         LocalFree(szName);
935 }
936
937 BOOL AFSModulesVerify(void)
938 {
939     CHAR filename[1024];
940     CHAR afsdVersion[128];
941     CHAR modVersion[128];
942     CHAR checkName[1024];
943     BOOL trustVerified = FALSE;
944     HMODULE hMods[1024];
945     HANDLE hProcess;
946     DWORD cbNeeded;
947     unsigned int i;
948     BOOL success = TRUE;
949     PCCERT_CONTEXT pCtxService = NULL;
950     HINSTANCE hPSAPI;
951     DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
952     BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
953     DWORD dummyLen, code;
954     DWORD cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
955     DWORD verifyServiceSig = TRUE;
956     HKEY parmKey;
957
958     hPSAPI = LoadLibrary("psapi");
959
960     if ( hPSAPI == NULL )
961         return FALSE;
962
963     if (!GetModuleFileName(NULL, filename, sizeof(filename)))
964         return FALSE;
965
966     if (GetVersionInfo(filename, afsdVersion, sizeof(afsdVersion)))
967         return FALSE;
968
969     afsi_log("%s version %s", filename, afsdVersion);
970
971     if (((FARPROC) pGetModuleFileNameExA =
972           GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
973          ((FARPROC) pEnumProcessModules =
974            GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
975     {
976         FreeLibrary(hPSAPI);
977         return FALSE;
978     }
979
980
981     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
982                         AFSREG_CLT_SVC_PARAM_SUBKEY,
983                         0, KEY_QUERY_VALUE, &parmKey);
984     if (code == ERROR_SUCCESS) {
985         dummyLen = sizeof(cacheSize);
986         code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
987                                (BYTE *) &cacheSize, &dummyLen);
988         RegCloseKey (parmKey);
989     }
990
991     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
992                          0, KEY_QUERY_VALUE, &parmKey);
993     if (code == ERROR_SUCCESS) {
994         dummyLen = sizeof(verifyServiceSig);
995         code = RegQueryValueEx(parmKey, "VerifyServiceSignature", NULL, NULL,
996                                 (BYTE *) &verifyServiceSig, &dummyLen);
997         RegCloseKey (parmKey);
998     }
999
1000     if (verifyServiceSig 
1001 #ifndef _WIN64
1002          && cacheSize < 716800
1003 #endif
1004          ) {
1005         trustVerified = VerifyTrust(filename);
1006     } else {
1007         afsi_log("Signature Verification disabled");
1008     }
1009
1010     if (trustVerified) {
1011         LoadCrypt32();
1012
1013         // get a certificate context for the signer of afsd_service.
1014         pCtxService = GetCertCtx(filename);
1015         if (pCtxService)
1016             LogCertCtx(pCtxService);
1017     }
1018
1019     // Get a list of all the modules in this process.
1020     hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1021                            FALSE, GetCurrentProcessId());
1022
1023     if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
1024     {
1025         afsi_log("Num of Process Modules: %d", (cbNeeded / sizeof(HMODULE)));
1026
1027         for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
1028         {
1029             char szModName[2048];
1030
1031             // Get the full path to the module's file.
1032             if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
1033             {
1034                 lstrcpy(checkName, szModName);
1035                 strlwr(checkName);
1036
1037                 if ( strstr(checkName, "afspthread.dll") ||
1038                      strstr(checkName, "afsauthent.dll") ||
1039                      strstr(checkName, "afsrpc.dll") ||
1040                      strstr(checkName, "libafsconf.dll") ||
1041                      strstr(checkName, "libosi.dll") )
1042                 {
1043                     if (GetVersionInfo(szModName, modVersion, sizeof(modVersion))) {
1044                         success = FALSE;
1045                         continue;
1046                     }
1047
1048                     afsi_log("%s version %s", szModName, modVersion);
1049                     if (strcmp(afsdVersion,modVersion)) {
1050                         afsi_log("Version mismatch: %s", szModName);
1051                         success = FALSE;
1052                     }
1053                     if ( trustVerified ) {
1054                         if ( !VerifyTrust(szModName) ) {
1055                             afsi_log("Signature Verification failed: %s", szModName);
1056                             success = FALSE;
1057                         } 
1058                         else if (pCtxService) {
1059                             PCCERT_CONTEXT pCtx = GetCertCtx(szModName);
1060
1061                             if (!pCtx || !pCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1062                                                                   pCtxService->pCertInfo,
1063                                                                   pCtx->pCertInfo)) {
1064                                 afsi_log("Certificate mismatch: %s", szModName);
1065                                 if (pCtx)
1066                                     LogCertCtx(pCtx);
1067                                 
1068                                 success = FALSE;
1069                             }
1070                             
1071                             if (pCtx)
1072                                 pCertFreeCertificateContext(pCtx);
1073                         }
1074                     }
1075                 }
1076             }
1077         }
1078     }
1079
1080     if (pCtxService) {
1081         pCertFreeCertificateContext(pCtxService);
1082         UnloadCrypt32();
1083     }
1084
1085     FreeLibrary(hPSAPI);
1086
1087     CloseHandle(hProcess);
1088     return success;
1089 }
1090
1091 /*
1092 control serviceex exists only on 2000/xp. These functions will be loaded dynamically.
1093 */
1094
1095 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerExFunc )(  LPCTSTR , LPHANDLER_FUNCTION_EX , LPVOID );
1096 typedef SERVICE_STATUS_HANDLE ( * RegisterServiceCtrlHandlerFunc   )(  LPCTSTR ,  LPHANDLER_FUNCTION );
1097
1098 RegisterServiceCtrlHandlerExFunc pRegisterServiceCtrlHandlerEx = NULL;
1099 RegisterServiceCtrlHandlerFunc   pRegisterServiceCtrlHandler   = NULL; 
1100
1101 VOID WINAPI
1102 afsd_Main(DWORD argc, LPTSTR *argv)
1103 {
1104     long code;
1105     char *reason;
1106 #ifdef JUMP
1107     int jmpret;
1108 #endif /* JUMP */
1109     HMODULE hHookDll;
1110     HMODULE hAdvApi32;
1111     HMODULE hKernel32;
1112
1113 #ifdef _DEBUG
1114     void afsd_DbgBreakAllocInit();
1115
1116     afsd_DbgBreakAllocInit();
1117     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
1118                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
1119 #endif 
1120
1121     afsd_SetUnhandledExceptionFilter();
1122        
1123     osi_InitPanic(afsd_notifier);
1124     osi_InitTraceOption();
1125
1126     hKernel32 = LoadLibrary("kernel32.dll");
1127     if (hKernel32 == NULL)
1128     {
1129         afsi_log("Fatal: cannot load kernel32.dll");
1130         return;
1131     }
1132     pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
1133
1134     GlobalStatus = 0;
1135
1136     afsi_start();
1137
1138     WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
1139     if ( GetLastError() == ERROR_ALREADY_EXISTS )
1140         afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
1141
1142 #ifndef NOTSERVICE
1143     hAdvApi32 = LoadLibrary("advapi32.dll");
1144     if (hAdvApi32 == NULL)
1145     {
1146         afsi_log("Fatal: cannot load advapi32.dll");
1147         return;
1148     }
1149
1150     if (bRunningAsService) {
1151         pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
1152         if (pRegisterServiceCtrlHandlerEx)
1153         {
1154             afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
1155             StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
1156         }
1157         else
1158         {
1159             StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
1160         }
1161
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);
1171     }
1172 #endif
1173
1174     LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
1175
1176 #ifdef REGISTER_POWER_NOTIFICATIONS
1177     {
1178         HKEY hkParm;
1179         DWORD code;
1180         DWORD dummyLen;
1181         int bpower = TRUE;
1182
1183         /* see if we should handle power notifications */
1184         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 
1185                             0, KEY_QUERY_VALUE, &hkParm);
1186         if (code == ERROR_SUCCESS) {
1187             dummyLen = sizeof(bpower);
1188             code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
1189                 (BYTE *) &bpower, &dummyLen);      
1190
1191             if(code != ERROR_SUCCESS)
1192                 bpower = TRUE;
1193
1194             RegCloseKey(hkParm);
1195         }
1196         /* create thread used to flush cache */
1197         if (bpower) {
1198             PowerNotificationThreadCreate();
1199             powerEventsRegistered = 1;
1200         }
1201     }
1202 #endif
1203
1204     /* Verify the versions of the DLLs which were loaded */
1205     if (!AFSModulesVerify()) {
1206         if (bRunningAsService) {
1207             ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1208             ServiceStatus.dwWin32ExitCode = NO_ERROR;
1209             ServiceStatus.dwCheckPoint = 0;
1210             ServiceStatus.dwWaitHint = 0;
1211             ServiceStatus.dwControlsAccepted = 0;
1212             SetServiceStatus(StatusHandle, &ServiceStatus);
1213         }
1214         LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
1215
1216         /* exit if initialization failed */
1217         return;
1218     }
1219
1220     /* allow an exit to be called prior to any initialization */
1221     hHookDll = cm_LoadAfsdHookLib();
1222     if (hHookDll)
1223     {
1224         BOOL hookRc = TRUE;
1225         AfsdInitHook initHook = ( AfsdInitHook ) GetProcAddress(hHookDll, AFSD_INIT_HOOK);
1226         if (initHook)
1227         {
1228             hookRc = initHook();
1229         }
1230         FreeLibrary(hHookDll);
1231         hHookDll = NULL;
1232
1233         if (hookRc == FALSE)
1234         {
1235             if (bRunningAsService) {
1236                 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1237                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1238                 ServiceStatus.dwCheckPoint = 0;
1239                 ServiceStatus.dwWaitHint = 0;
1240                 ServiceStatus.dwControlsAccepted = 0;
1241                 SetServiceStatus(StatusHandle, &ServiceStatus);
1242             }       
1243             /* exit if initialization failed */
1244             return;
1245         }
1246         else
1247         {
1248             /* allow another 120 seconds to start */
1249             if (bRunningAsService) {
1250                 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1251                 ServiceStatus.dwServiceSpecificExitCode = 0;
1252                 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1253                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1254                 ServiceStatus.dwCheckPoint = 2;
1255                 ServiceStatus.dwWaitHint = 120000;
1256                 /* accept Power Events */
1257                 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1258                 SetServiceStatus(StatusHandle, &ServiceStatus);
1259             }
1260         }
1261     }
1262
1263     /* Perform Volume Status Notification Initialization */
1264     cm_VolStatus_Initialization();
1265
1266 #ifdef JUMP
1267     MainThreadId = GetCurrentThreadId();
1268     jmpret = setjmp(notifier_jmp);
1269
1270     if (jmpret == 0) 
1271 #endif /* JUMP */
1272     {
1273         code = afsd_InitCM(&reason);
1274         if (code != 0) {
1275             afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
1276             osi_panic(reason, __FILE__, __LINE__);
1277         }
1278
1279 #ifndef NOTSERVICE
1280         if (bRunningAsService) {
1281             ServiceStatus.dwCheckPoint = 3;
1282             ServiceStatus.dwWaitHint = 30000;
1283             SetServiceStatus(StatusHandle, &ServiceStatus);
1284         }
1285 #endif
1286         /* allow an exit to be called post rx initialization */
1287         hHookDll = cm_LoadAfsdHookLib();
1288         if (hHookDll)
1289         {
1290             BOOL hookRc = TRUE;
1291             AfsdRxStartedHook rxStartedHook = ( AfsdRxStartedHook ) GetProcAddress(hHookDll, AFSD_RX_STARTED_HOOK);
1292             if (rxStartedHook)
1293             {
1294                 hookRc = rxStartedHook();
1295             }
1296             FreeLibrary(hHookDll);
1297             hHookDll = NULL;
1298
1299             if (hookRc == FALSE)
1300             {
1301                 if (bRunningAsService) {
1302                     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1303                     ServiceStatus.dwWin32ExitCode = NO_ERROR;
1304                     ServiceStatus.dwCheckPoint = 0;
1305                     ServiceStatus.dwWaitHint = 0;
1306                     ServiceStatus.dwControlsAccepted = 0;
1307                     SetServiceStatus(StatusHandle, &ServiceStatus);
1308                 }   
1309                 /* exit if initialization failed */
1310                 return;
1311             }
1312         }
1313
1314 #ifndef NOTSERVICE
1315         if (bRunningAsService) {
1316             ServiceStatus.dwCheckPoint = 4;
1317             ServiceStatus.dwWaitHint = 15000;
1318             SetServiceStatus(StatusHandle, &ServiceStatus);
1319         }
1320 #endif
1321
1322         /* Notify any volume status handlers that the cache manager has started */
1323         cm_VolStatus_Service_Started();
1324
1325         code = afsd_InitSMB(&reason, MessageBox);
1326         if (code != 0) {
1327             afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
1328             osi_panic(reason, __FILE__, __LINE__);
1329         }
1330
1331         /* allow an exit to be called post smb initialization */
1332         hHookDll = cm_LoadAfsdHookLib();
1333         if (hHookDll)
1334         {
1335             BOOL hookRc = TRUE;
1336             AfsdSmbStartedHook smbStartedHook = ( AfsdSmbStartedHook ) GetProcAddress(hHookDll, AFSD_SMB_STARTED_HOOK);
1337             if (smbStartedHook)
1338             {
1339                 hookRc = smbStartedHook();
1340             }
1341             FreeLibrary(hHookDll);
1342             hHookDll = NULL;
1343
1344             if (hookRc == FALSE)
1345             {
1346                 if (bRunningAsService) {
1347                     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1348                     ServiceStatus.dwWin32ExitCode = NO_ERROR;
1349                     ServiceStatus.dwCheckPoint = 0;
1350                     ServiceStatus.dwWaitHint = 0;
1351                     ServiceStatus.dwControlsAccepted = 0;
1352                     SetServiceStatus(StatusHandle, &ServiceStatus);
1353                 }   
1354                 /* exit if initialization failed */
1355                 return;
1356             }
1357         }
1358
1359         MountGlobalDrives();
1360
1361         code = afsd_InitDaemons(&reason);
1362         if (code != 0) {
1363             afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
1364                         osi_panic(reason, __FILE__, __LINE__);
1365         }
1366
1367 #ifndef NOTSERVICE
1368         if (bRunningAsService) {
1369             ServiceStatus.dwCurrentState = SERVICE_RUNNING;
1370             ServiceStatus.dwWin32ExitCode = NO_ERROR;
1371             ServiceStatus.dwCheckPoint = 5;
1372             ServiceStatus.dwWaitHint = 0;
1373
1374             /* accept Power events */
1375             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
1376             SetServiceStatus(StatusHandle, &ServiceStatus);
1377         }
1378 #endif  
1379
1380         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
1381     }
1382
1383     /* allow an exit to be called when started */
1384     hHookDll = cm_LoadAfsdHookLib();
1385     if (hHookDll)
1386     {
1387         BOOL hookRc = TRUE;
1388         AfsdStartedHook startedHook = ( AfsdStartedHook ) GetProcAddress(hHookDll, AFSD_STARTED_HOOK);
1389         if (startedHook)
1390         {
1391             hookRc = startedHook();
1392         }
1393         FreeLibrary(hHookDll);
1394         hHookDll = NULL;
1395
1396         if (hookRc == FALSE)
1397         {
1398             if (bRunningAsService) {
1399                 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1400                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
1401                 ServiceStatus.dwCheckPoint = 0;
1402                 ServiceStatus.dwWaitHint = 0;
1403                 ServiceStatus.dwControlsAccepted = 0;
1404                 SetServiceStatus(StatusHandle, &ServiceStatus);
1405             }                       
1406             /* exit if initialization failed */
1407             return;
1408         }
1409     }
1410
1411     WaitForSingleObject(WaitToTerminate, INFINITE);
1412
1413     if (bRunningAsService) {
1414         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1415         ServiceStatus.dwWin32ExitCode = NO_ERROR;
1416         ServiceStatus.dwCheckPoint = 6;
1417         ServiceStatus.dwWaitHint = 120000;
1418         ServiceStatus.dwControlsAccepted = 0;
1419         SetServiceStatus(StatusHandle, &ServiceStatus);
1420     }
1421     afsi_log("Received Termination Signal, Stopping Service");
1422
1423     if ( GlobalStatus )
1424         LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP);
1425     else
1426         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING);
1427
1428     /* allow an exit to be called prior to stopping the service */
1429     hHookDll = cm_LoadAfsdHookLib();
1430     if (hHookDll)
1431     {
1432         BOOL hookRc = TRUE;
1433         AfsdStoppingHook stoppingHook = ( AfsdStoppingHook ) GetProcAddress(hHookDll, AFSD_STOPPING_HOOK);
1434         if (stoppingHook)
1435         {
1436             hookRc = stoppingHook();
1437         }
1438         FreeLibrary(hHookDll);
1439         hHookDll = NULL;
1440     }
1441
1442
1443 #ifdef AFS_FREELANCE_CLIENT
1444     cm_FreelanceShutdown();
1445     afsi_log("Freelance Shutdown complete");
1446 #endif
1447
1448     DismountGlobalDrives();
1449     afsi_log("Global Drives dismounted");
1450                                          
1451     smb_Shutdown();                      
1452     afsi_log("smb shutdown complete");   
1453                                          
1454     RpcShutdown();                       
1455
1456     cm_ReleaseAllLocks();
1457
1458     cm_DaemonShutdown();                 
1459     afsi_log("Daemon shutdown complete");
1460     
1461     buf_Shutdown();                      
1462     afsi_log("Buffer shutdown complete");
1463                                          
1464     afsd_ShutdownCM();
1465
1466     cm_ShutdownMappedMemory();           
1467
1468     rx_Finalize();
1469     afsi_log("rx finalization complete");
1470
1471 #ifdef  REGISTER_POWER_NOTIFICATIONS
1472     /* terminate thread used to flush cache */
1473     if (powerEventsRegistered)
1474         PowerNotificationThreadExit();
1475 #endif
1476
1477     cm_DirDumpStats();
1478 #ifdef USE_BPLUS
1479     cm_BPlusDumpStats();
1480 #endif
1481
1482     /* Notify any Volume Status Handlers that we are stopped */
1483     cm_VolStatus_Service_Stopped();
1484
1485     /* Cleanup any Volume Status Notification Handler */
1486     cm_VolStatus_Finalize();
1487
1488     /* allow an exit to be called after stopping the service */
1489     hHookDll = cm_LoadAfsdHookLib();
1490     if (hHookDll)
1491     {
1492         BOOL hookRc = TRUE;
1493         AfsdStoppedHook stoppedHook = ( AfsdStoppedHook ) GetProcAddress(hHookDll, AFSD_STOPPED_HOOK);
1494         if (stoppedHook)
1495         {
1496             hookRc = stoppedHook();
1497         }
1498         FreeLibrary(hHookDll);
1499         hHookDll = NULL;
1500     }
1501
1502     /* Remove the ExceptionFilter */
1503     SetUnhandledExceptionFilter(NULL);
1504
1505     if (bRunningAsService) {
1506         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
1507         ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
1508         ServiceStatus.dwCheckPoint = 7;
1509         ServiceStatus.dwWaitHint = 0;
1510         ServiceStatus.dwControlsAccepted = 0;
1511         SetServiceStatus(StatusHandle, &ServiceStatus);
1512     }
1513 }       
1514
1515 DWORD __stdcall afsdMain_thread(void* notUsed)
1516 {
1517     char * argv[2] = {AFS_DAEMON_SERVICE_NAME, NULL};
1518     afsd_Main(1, (LPTSTR*)argv);
1519     return(0);
1520 }
1521
1522 void usage(void)
1523 {
1524     fprintf(stderr, "afsd_service.exe [--validate-cache <cache-path>]");
1525 }
1526
1527 int
1528 main(int argc, char * argv[])
1529 {
1530     static SERVICE_TABLE_ENTRY dispatchTable[] = {
1531         {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
1532         {NULL, NULL}
1533     };
1534     int i;
1535
1536     for (i = 1; i < argc; i++) {
1537         if (!stricmp(argv[i],"--validate-cache")) {
1538             if (++i != argc - 1) {
1539                 usage();
1540                 return(1);
1541             }
1542
1543             return cm_ValidateMappedMemory(argv[i]);
1544         } else {
1545             usage();
1546             return(1);
1547         }
1548     }
1549
1550     if (!StartServiceCtrlDispatcher(dispatchTable))
1551     {
1552         LONG status = GetLastError();
1553         if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1554         {
1555             DWORD tid;
1556
1557             bRunningAsService = FALSE;
1558
1559             hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
1560                 
1561             printf("Hit <Enter> to terminate OpenAFS Client Service\n");
1562             getchar();  
1563             SetEvent(WaitToTerminate);
1564         }
1565     }
1566
1567     if ( hAFSDMainThread ) {
1568         WaitForSingleObject( hAFSDMainThread, INFINITE );
1569         CloseHandle( hAFSDMainThread );
1570     }
1571     return(0);
1572 }