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