windows-fw-service-test-20051017
[openafs.git] / src / WINNT / afsd / cm_daemon.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #include <winsock2.h>
16 #else
17 #include <netdb.h>
18 #endif /* !DJGPP */
19 #include <stdlib.h>
20 #include <malloc.h>
21 #include <string.h>
22
23 #include <rx/rx.h>
24 #include <rx/rx_prototypes.h>
25
26 #include "afsd.h"
27 #include "afsicf.h"
28
29 long cm_daemonCheckInterval = 30;
30 long cm_daemonTokenCheckInterval = 180;
31
32 osi_rwlock_t cm_daemonLock;
33
34 long cm_bkgQueueCount;          /* # of queued requests */
35
36 int cm_bkgWaitingForCount;      /* true if someone's waiting for cm_bkgQueueCount to drop */
37
38 cm_bkgRequest_t *cm_bkgListp;           /* first elt in the list of requests */
39 cm_bkgRequest_t *cm_bkgListEndp;        /* last elt in the list of requests */
40
41 static int daemon_ShutdownFlag = 0;
42
43 void cm_BkgDaemon(long parm)
44 {
45     cm_bkgRequest_t *rp;
46
47     rx_StartClientThread();
48
49     lock_ObtainWrite(&cm_daemonLock);
50     while (daemon_ShutdownFlag == 0) {
51         if (!cm_bkgListEndp) {
52             osi_SleepW((long) &cm_bkgListp, &cm_daemonLock);
53             lock_ObtainWrite(&cm_daemonLock);
54             continue;
55         }
56                 
57         /* we found a request */
58         rp = cm_bkgListEndp;
59         cm_bkgListEndp = (cm_bkgRequest_t *) osi_QPrev(&rp->q);
60         osi_QRemove((osi_queue_t **) &cm_bkgListp, &rp->q);
61         osi_assert(cm_bkgQueueCount-- > 0);
62         lock_ReleaseWrite(&cm_daemonLock);
63
64         (*rp->procp)(rp->scp, rp->p1, rp->p2, rp->p3, rp->p4, rp->userp);
65                 
66         cm_ReleaseUser(rp->userp);
67         cm_ReleaseSCache(rp->scp);
68         free(rp);
69
70         lock_ObtainWrite(&cm_daemonLock);
71     }
72     lock_ReleaseWrite(&cm_daemonLock);
73 }
74
75 void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, long p1, long p2, long p3, long p4,
76         cm_user_t *userp)
77 {
78     cm_bkgRequest_t *rp;
79         
80     rp = malloc(sizeof(*rp));
81     memset(rp, 0, sizeof(*rp));
82         
83     cm_HoldSCache(scp);
84     rp->scp = scp;
85     cm_HoldUser(userp);
86     rp->userp = userp;
87     rp->procp = procp;
88     rp->p1 = p1;
89     rp->p2 = p2;
90     rp->p3 = p3;
91     rp->p4 = p4;
92
93     lock_ObtainWrite(&cm_daemonLock);
94     cm_bkgQueueCount++;
95     osi_QAdd((osi_queue_t **) &cm_bkgListp, &rp->q);
96     if (!cm_bkgListEndp) 
97         cm_bkgListEndp = rp;
98     lock_ReleaseWrite(&cm_daemonLock);
99
100     osi_Wakeup((long) &cm_bkgListp);
101 }
102
103 static int
104 IsWindowsFirewallPresent(void)
105 {
106     SC_HANDLE scm;
107     SC_HANDLE svc;
108     BOOLEAN flag;
109     BOOLEAN result = FALSE;
110     LPQUERY_SERVICE_CONFIG pConfig = NULL;
111     DWORD BufSize;
112     LONG status;
113
114     /* Open services manager */
115     scm = OpenSCManager(NULL, NULL, GENERIC_READ);
116     if (!scm) return FALSE;
117
118     /* Open Windows Firewall service */
119     svc = OpenService(scm, "SharedAccess", SERVICE_QUERY_CONFIG);
120     if (!svc)
121         goto close_scm;
122
123     /* Query Windows Firewall service config, first just to get buffer size */
124     /* Expected to fail, so don't test return value */
125     (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
126     status = GetLastError();
127     if (status != ERROR_INSUFFICIENT_BUFFER)
128         goto close_svc;
129
130     /* Allocate buffer */
131     pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
132     if (!pConfig)
133         goto close_svc;
134
135     /* Query Windows Firewall service config, this time for real */
136     flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
137     if (!flag)
138         goto free_pConfig;
139
140     /* Is it autostart? */
141     if (pConfig->dwStartType < SERVICE_DEMAND_START)
142         result = TRUE;
143
144   free_pConfig:
145     GlobalFree(pConfig);
146   close_svc:
147     CloseServiceHandle(svc);
148   close_scm:
149     CloseServiceHandle(scm);
150
151     return result;
152 }
153
154 /* periodic check daemon */
155 void cm_Daemon(long parm)
156 {
157     unsigned long now;
158     unsigned long lastLockCheck;
159     unsigned long lastVolCheck;
160     unsigned long lastCBExpirationCheck;
161     unsigned long lastDownServerCheck;
162     unsigned long lastUpServerCheck;
163     unsigned long lastTokenCacheCheck;
164     char thostName[200];
165     unsigned long code;
166     struct hostent *thp;
167     HMODULE hHookDll;
168     int configureFirewall = IsWindowsFirewallPresent();
169
170     /* ping all file servers, up or down, with unauthenticated connection,
171      * to find out whether we have all our callbacks from the server still.
172      * Also, ping down VLDBs.
173      */
174     /*
175      * Seed the random number generator with our own address, so that
176      * clients starting at the same time don't all do vol checks at the
177      * same time.
178      */
179     gethostname(thostName, sizeof(thostName));
180     thp = gethostbyname(thostName);
181     if (thp == NULL)    /* In djgpp, gethostname returns the netbios
182                            name of the machine.  gethostbyname will fail
183                            looking this up if it differs from DNS name. */
184         code = 0;
185     else
186         memcpy(&code, thp->h_addr_list[0], 4);
187     srand(ntohl(code));
188
189     now = osi_Time();
190     lastVolCheck = now - 1800 + (rand() % 3600);
191     lastCBExpirationCheck = now - 60 + (rand() % 60);
192     lastLockCheck = now - 60 + (rand() % 60);
193     lastDownServerCheck = now - cm_daemonCheckInterval/2 + (rand() % cm_daemonCheckInterval);
194     lastUpServerCheck = now - 1800 + (rand() % 3600);
195     lastTokenCacheCheck = now - cm_daemonTokenCheckInterval/2 + (rand() % cm_daemonTokenCheckInterval);
196
197     while (daemon_ShutdownFlag == 0) {
198         thrd_Sleep(30 * 1000);          /* sleep 30 seconds */
199         if (daemon_ShutdownFlag == 1)
200             return;
201
202         if (configureFirewall) {
203             /* Open Microsoft Firewall to allow in port 7001 */
204             switch (icf_CheckAndAddAFSPorts(AFS_PORTSET_CLIENT)) {
205             case 0:
206                 afsi_log("Windows Firewall Configuration succeeded");
207                 configureFirewall = 0;
208                 break;
209             case 1:
210                 afsi_log("Invalid Windows Firewall Port Set");
211                 break;
212             case 2:
213                 afsi_log("Unable to open Windows Firewall Profile");
214                 break;
215             case 3:
216                 afsi_log("Unable to create/modify Windows Firewall Port entries");
217                 break;
218             default:
219                 afsi_log("Unknown Windows Firewall Configuration error");
220             }
221         }
222
223         /* find out what time it is */
224         now = osi_Time();
225
226         /* check down servers */
227         if (now > lastDownServerCheck + cm_daemonCheckInterval) {
228             lastDownServerCheck = now;
229             cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS, NULL);
230         }
231
232         /* check up servers */
233         if (now > lastUpServerCheck + 3600) {
234             lastUpServerCheck = now;
235             cm_CheckServers(CM_FLAG_CHECKUPSERVERS, NULL);
236         }
237
238         if (now > lastVolCheck + 3600) {
239             lastVolCheck = now;
240             cm_CheckVolumes();
241         }
242
243         if (now > lastCBExpirationCheck + 60) {
244             lastCBExpirationCheck = now;
245             cm_CheckCBExpiration();
246         }
247
248         if (now > lastLockCheck + 60) {
249             lastLockCheck = now;
250             cm_CheckLocks();
251         }
252
253         if (now > lastTokenCacheCheck + cm_daemonTokenCheckInterval) {
254             lastTokenCacheCheck = now;
255             cm_CheckTokenCache(now);
256         }
257
258         /* allow an exit to be called prior to stopping the service */
259         hHookDll = LoadLibrary(AFSD_HOOK_DLL);
260         if (hHookDll)
261         {
262             BOOL hookRc = TRUE;
263             AfsdDaemonHook daemonHook = ( AfsdDaemonHook ) GetProcAddress(hHookDll, AFSD_DAEMON_HOOK);
264             if (daemonHook)
265             {
266                 hookRc = daemonHook();
267             }
268             FreeLibrary(hHookDll);
269             hHookDll = NULL;
270
271             if (hookRc == FALSE)
272             {
273                 SetEvent(WaitToTerminate);
274             }
275         }
276     }
277 }       
278
279 void cm_DaemonShutdown(void)
280 {
281     daemon_ShutdownFlag = 1;
282 }
283
284 void cm_InitDaemon(int nDaemons)
285 {
286     static osi_once_t once;
287     long pid;
288     thread_t phandle;
289     int i;
290         
291     if (osi_Once(&once)) {
292         lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock");
293         osi_EndOnce(&once);
294                 
295         /* creating pinging daemon */
296         phandle = thrd_Create((SecurityAttrib) 0, 0,
297                                (ThreadFunc) cm_Daemon, 0, 0, &pid, "cm_Daemon");
298         osi_assert(phandle != NULL);
299
300         thrd_CloseHandle(phandle);
301         for(i=0; i < nDaemons; i++) {
302             phandle = thrd_Create((SecurityAttrib) 0, 0,
303                                    (ThreadFunc) cm_BkgDaemon, 0, 0, &pid,
304                                    "cm_BkgDaemon");
305             osi_assert(phandle != NULL);
306             thrd_CloseHandle(phandle);
307         }
308     }
309 }