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