]>
Commit | Line | Data |
---|---|---|
c9d2d929 | 1 | /* |
7f0064bd A |
2 | * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. |
3 | * | |
c9d2d929 | 4 | * @APPLE_LICENSE_HEADER_START@ |
7f0064bd | 5 | * |
c9d2d929 A |
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. | |
7f0064bd | 12 | * |
c9d2d929 A |
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 | |
7f0064bd | 19 | * limitations under the License. |
c9d2d929 A |
20 | * |
21 | * @APPLE_LICENSE_HEADER_END@ | |
7f0064bd A |
22 | |
23 | Change History (most recent first): | |
24 | ||
25 | $Log: Firewall.cpp,v $ | |
4aea607d A |
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 | ||
7f0064bd A |
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 | ||
4aea607d A |
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 | |
7f0064bd A |
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 | } |