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