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