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