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