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