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