]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/SystemService/Firewall.cpp
mDNSResponder-108.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / SystemService / Firewall.cpp
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: Firewall.cpp,v $
26 Revision 1.3 2005/09/29 06:33:54 herscher
27 <rdar://problem/4278931> Fix compilation error when using latest Microsoft Platform SDK.
28
29 Revision 1.2 2004/09/15 09:39:53 shersche
30 Retry the method INetFwPolicy::get_CurrentProfile on error
31
32 Revision 1.1 2004/09/13 07:32:31 shersche
33 Wrapper for Windows Firewall API code
34
35
36 */
37
38 // <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
39
40 #if !defined(_WIN32_DCOM)
41 # define _WIN32_DCOM
42 #endif
43
44
45 #if !defined(_WSPIAPI_COUNTOF)
46 # define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
47 #endif
48
49 #include "Firewall.h"
50 #include <windows.h>
51 #include <crtdbg.h>
52 #include <netfw.h>
53 #include <objbase.h>
54 #include <oleauto.h>
55
56
57 static const int kMaxTries = 30;
58 static const int kRetrySleepPeriod = 1 * 1000; // 1 second
59
60
61 static OSStatus
62 mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
63 {
64 INetFwMgr * fwMgr = NULL;
65 INetFwPolicy * fwPolicy = NULL;
66 int numRetries = 0;
67 HRESULT err = kNoErr;
68
69 _ASSERT(fwProfile != NULL);
70
71 *fwProfile = NULL;
72
73 // Use COM to get a reference to the firewall settings manager. This
74 // call will fail on anything other than XP SP2
75
76 err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
77 require(SUCCEEDED(err), exit);
78
79 // Use the reference to get the local firewall policy
80
81 err = fwMgr->get_LocalPolicy(&fwPolicy);
82 require(SUCCEEDED(err), exit);
83
84 // Use the reference to get the extant profile. Empirical evidence
85 // suggests that there is the potential for a race condition when a system
86 // service whose startup type is automatic calls this method.
87 // This is true even when the service declares itself to be dependent
88 // on the firewall service. Re-trying the method will succeed within
89 // a few seconds.
90
91 do
92 {
93 err = fwPolicy->get_CurrentProfile(fwProfile);
94
95 if (err)
96 {
97 Sleep(kRetrySleepPeriod);
98 }
99 }
100 while (err && (numRetries++ < kMaxTries));
101
102 require(SUCCEEDED(err), exit);
103
104 err = kNoErr;
105
106 exit:
107
108 // Release temporary COM objects
109
110 if (fwPolicy != NULL)
111 {
112 fwPolicy->Release();
113 }
114
115 if (fwMgr != NULL)
116 {
117 fwMgr->Release();
118 }
119
120 return err;
121 }
122
123
124 static void
125 mDNSFirewallCleanup
126 (
127 IN INetFwProfile * fwProfile
128 )
129 {
130 // Call Release on the COM reference.
131
132 if (fwProfile != NULL)
133 {
134 fwProfile->Release();
135 }
136 }
137
138
139 static OSStatus
140 mDNSFirewallAppIsEnabled
141 (
142 IN INetFwProfile * fwProfile,
143 IN const wchar_t * fwProcessImageFileName,
144 OUT BOOL * fwAppEnabled
145 )
146 {
147 BSTR fwBstrProcessImageFileName = NULL;
148 VARIANT_BOOL fwEnabled;
149 INetFwAuthorizedApplication * fwApp = NULL;
150 INetFwAuthorizedApplications* fwApps = NULL;
151 OSStatus err = kNoErr;
152
153 _ASSERT(fwProfile != NULL);
154 _ASSERT(fwProcessImageFileName != NULL);
155 _ASSERT(fwAppEnabled != NULL);
156
157 *fwAppEnabled = FALSE;
158
159 // Get the list of authorized applications
160
161 err = fwProfile->get_AuthorizedApplications(&fwApps);
162 require(SUCCEEDED(err), exit);
163
164 fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
165 require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
166
167 // Look for us
168
169 err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
170
171 if (SUCCEEDED(err))
172 {
173 // It's listed, but is it enabled?
174
175 err = fwApp->get_Enabled(&fwEnabled);
176 require(SUCCEEDED(err), exit);
177
178 if (fwEnabled != VARIANT_FALSE)
179 {
180 // Yes, it's enabled
181
182 *fwAppEnabled = TRUE;
183 }
184 }
185
186 err = kNoErr;
187
188 exit:
189
190 // Deallocate the BSTR
191
192 SysFreeString(fwBstrProcessImageFileName);
193
194 // Release the COM objects
195
196 if (fwApp != NULL)
197 {
198 fwApp->Release();
199 }
200
201 if (fwApps != NULL)
202 {
203 fwApps->Release();
204 }
205
206 return err;
207 }
208
209
210 static OSStatus
211 mDNSFirewallAddApp
212 (
213 IN INetFwProfile * fwProfile,
214 IN const wchar_t * fwProcessImageFileName,
215 IN const wchar_t * fwName
216 )
217 {
218 BOOL fwAppEnabled;
219 BSTR fwBstrName = NULL;
220 BSTR fwBstrProcessImageFileName = NULL;
221 INetFwAuthorizedApplication * fwApp = NULL;
222 INetFwAuthorizedApplications* fwApps = NULL;
223 OSStatus err = S_OK;
224
225 _ASSERT(fwProfile != NULL);
226 _ASSERT(fwProcessImageFileName != NULL);
227 _ASSERT(fwName != NULL);
228
229 // First check to see if the application is already authorized.
230 err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
231 require_noerr(err, exit);
232
233 // Only add the application if it isn't enabled
234
235 if (!fwAppEnabled)
236 {
237 // Get the list of authorized applications
238
239 err = fwProfile->get_AuthorizedApplications(&fwApps);
240 require(SUCCEEDED(err), exit);
241
242 // Create an instance of an authorized application.
243
244 err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
245 require(SUCCEEDED(err), exit);
246
247 fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
248 require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
249
250 // Set the executable file name
251
252 err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
253 require(SUCCEEDED(err), exit);
254
255 fwBstrName = SysAllocString(fwName);
256 require_action(SysStringLen(fwBstrName) > 0, exit, err = kNoMemoryErr);
257
258 // Set the friendly name
259
260 err = fwApp->put_Name(fwBstrName);
261 require(SUCCEEDED(err), exit);
262
263 // Now add the application
264
265 err = fwApps->Add(fwApp);
266 require(SUCCEEDED(err), exit);
267 }
268
269 err = kNoErr;
270
271 exit:
272
273 // Deallocate the BSTR objects
274
275 SysFreeString(fwBstrName);
276 SysFreeString(fwBstrProcessImageFileName);
277
278 // Release the COM objects
279
280 if (fwApp != NULL)
281 {
282 fwApp->Release();
283 }
284
285 if (fwApps != NULL)
286 {
287 fwApps->Release();
288 }
289
290 return err;
291 }
292
293
294 OSStatus
295 mDNSAddToFirewall
296 (
297 LPWSTR executable,
298 LPWSTR name
299 )
300 {
301 INetFwProfile * fwProfile = NULL;
302 HRESULT comInit = E_FAIL;
303 OSStatus err = kNoErr;
304
305 // Initialize COM.
306
307 comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
308
309 // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
310 // initialized with a different mode.
311
312 if (comInit != RPC_E_CHANGED_MODE)
313 {
314 err = comInit;
315 require(SUCCEEDED(err), exit);
316 }
317
318 // Connect to the firewall
319
320 err = mDNSFirewallInitialize(&fwProfile);
321 require_noerr(err, exit);
322
323 // Add us to the list of exempt programs
324
325 err = mDNSFirewallAddApp( fwProfile, executable, name );
326 require_noerr(err, exit);
327
328 exit:
329
330 // Disconnect from the firewall
331
332 mDNSFirewallCleanup(fwProfile);
333
334 // De-initialize COM
335
336 if (SUCCEEDED(comInit))
337 {
338 CoUninitialize();
339 }
340
341 return err;
342 }