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