]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/SystemService/Firewall.cpp
mDNSResponder-87.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.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 #define _WIN32_DCOM
36
37 #include "Firewall.h"
38 #include <windows.h>
39 #include <crtdbg.h>
40 #include <netfw.h>
41 #include <objbase.h>
42 #include <oleauto.h>
43
44
45 static const int kMaxTries = 30;
46 static const int kRetrySleepPeriod = 1 * 1000; // 1 second
47
48
49 static OSStatus
50 mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
51 {
52 INetFwMgr * fwMgr = NULL;
53 INetFwPolicy * fwPolicy = NULL;
54 int numRetries = 0;
55 HRESULT err = kNoErr;
56
57 _ASSERT(fwProfile != NULL);
58
59 *fwProfile = NULL;
60
61 // Use COM to get a reference to the firewall settings manager. This
62 // call will fail on anything other than XP SP2
63
64 err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
65 require(SUCCEEDED(err), exit);
66
67 // Use the reference to get the local firewall policy
68
69 err = fwMgr->get_LocalPolicy(&fwPolicy);
70 require(SUCCEEDED(err), exit);
71
72 // Use the reference to get the extant profile. Empirical evidence
73 // suggests that there is the potential for a race condition when a system
74 // service whose startup type is automatic calls this method.
75 // This is true even when the service declares itself to be dependent
76 // on the firewall service. Re-trying the method will succeed within
77 // a few seconds.
78
79 do
80 {
81 err = fwPolicy->get_CurrentProfile(fwProfile);
82
83 if (err)
84 {
85 Sleep(kRetrySleepPeriod);
86 }
87 }
88 while (err && (numRetries++ < kMaxTries));
89
90 require(SUCCEEDED(err), exit);
91
92 err = kNoErr;
93
94 exit:
95
96 // Release temporary COM objects
97
98 if (fwPolicy != NULL)
99 {
100 fwPolicy->Release();
101 }
102
103 if (fwMgr != NULL)
104 {
105 fwMgr->Release();
106 }
107
108 return err;
109 }
110
111
112 static void
113 mDNSFirewallCleanup
114 (
115 IN INetFwProfile * fwProfile
116 )
117 {
118 // Call Release on the COM reference.
119
120 if (fwProfile != NULL)
121 {
122 fwProfile->Release();
123 }
124 }
125
126
127 static OSStatus
128 mDNSFirewallAppIsEnabled
129 (
130 IN INetFwProfile * fwProfile,
131 IN const wchar_t * fwProcessImageFileName,
132 OUT BOOL * fwAppEnabled
133 )
134 {
135 BSTR fwBstrProcessImageFileName = NULL;
136 VARIANT_BOOL fwEnabled;
137 INetFwAuthorizedApplication * fwApp = NULL;
138 INetFwAuthorizedApplications* fwApps = NULL;
139 OSStatus err = kNoErr;
140
141 _ASSERT(fwProfile != NULL);
142 _ASSERT(fwProcessImageFileName != NULL);
143 _ASSERT(fwAppEnabled != NULL);
144
145 *fwAppEnabled = FALSE;
146
147 // Get the list of authorized applications
148
149 err = fwProfile->get_AuthorizedApplications(&fwApps);
150 require(SUCCEEDED(err), exit);
151
152 fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
153 require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
154
155 // Look for us
156
157 err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
158
159 if (SUCCEEDED(err))
160 {
161 // It's listed, but is it enabled?
162
163 err = fwApp->get_Enabled(&fwEnabled);
164 require(SUCCEEDED(err), exit);
165
166 if (fwEnabled != VARIANT_FALSE)
167 {
168 // Yes, it's enabled
169
170 *fwAppEnabled = TRUE;
171 }
172 }
173
174 err = kNoErr;
175
176 exit:
177
178 // Deallocate the BSTR
179
180 SysFreeString(fwBstrProcessImageFileName);
181
182 // Release the COM objects
183
184 if (fwApp != NULL)
185 {
186 fwApp->Release();
187 }
188
189 if (fwApps != NULL)
190 {
191 fwApps->Release();
192 }
193
194 return err;
195 }
196
197
198 static OSStatus
199 mDNSFirewallAddApp
200 (
201 IN INetFwProfile * fwProfile,
202 IN const wchar_t * fwProcessImageFileName,
203 IN const wchar_t * fwName
204 )
205 {
206 BOOL fwAppEnabled;
207 BSTR fwBstrName = NULL;
208 BSTR fwBstrProcessImageFileName = NULL;
209 INetFwAuthorizedApplication * fwApp = NULL;
210 INetFwAuthorizedApplications* fwApps = NULL;
211 OSStatus err = S_OK;
212
213 _ASSERT(fwProfile != NULL);
214 _ASSERT(fwProcessImageFileName != NULL);
215 _ASSERT(fwName != NULL);
216
217 // First check to see if the application is already authorized.
218 err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
219 require_noerr(err, exit);
220
221 // Only add the application if it isn't enabled
222
223 if (!fwAppEnabled)
224 {
225 // Get the list of authorized applications
226
227 err = fwProfile->get_AuthorizedApplications(&fwApps);
228 require(SUCCEEDED(err), exit);
229
230 // Create an instance of an authorized application.
231
232 err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
233 require(SUCCEEDED(err), exit);
234
235 fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
236 require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
237
238 // Set the executable file name
239
240 err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
241 require(SUCCEEDED(err), exit);
242
243 fwBstrName = SysAllocString(fwName);
244 require_action(SysStringLen(fwBstrName) > 0, exit, err = kNoMemoryErr);
245
246 // Set the friendly name
247
248 err = fwApp->put_Name(fwBstrName);
249 require(SUCCEEDED(err), exit);
250
251 // Now add the application
252
253 err = fwApps->Add(fwApp);
254 require(SUCCEEDED(err), exit);
255 }
256
257 err = kNoErr;
258
259 exit:
260
261 // Deallocate the BSTR objects
262
263 SysFreeString(fwBstrName);
264 SysFreeString(fwBstrProcessImageFileName);
265
266 // Release the COM objects
267
268 if (fwApp != NULL)
269 {
270 fwApp->Release();
271 }
272
273 if (fwApps != NULL)
274 {
275 fwApps->Release();
276 }
277
278 return err;
279 }
280
281
282 OSStatus
283 mDNSAddToFirewall
284 (
285 LPWSTR executable,
286 LPWSTR name
287 )
288 {
289 INetFwProfile * fwProfile = NULL;
290 HRESULT comInit = E_FAIL;
291 OSStatus err = kNoErr;
292
293 // Initialize COM.
294
295 comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
296
297 // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
298 // initialized with a different mode.
299
300 if (comInit != RPC_E_CHANGED_MODE)
301 {
302 err = comInit;
303 require(SUCCEEDED(err), exit);
304 }
305
306 // Connect to the firewall
307
308 err = mDNSFirewallInitialize(&fwProfile);
309 require_noerr(err, exit);
310
311 // Add us to the list of exempt programs
312
313 err = mDNSFirewallAddApp( fwProfile, executable, name );
314 require_noerr(err, exit);
315
316 exit:
317
318 // Disconnect from the firewall
319
320 mDNSFirewallCleanup(fwProfile);
321
322 // De-initialize COM
323
324 if (SUCCEEDED(comInit))
325 {
326 CoUninitialize();
327 }
328
329 return err;
330 }