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