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