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