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