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