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