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