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