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