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