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