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