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