1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
19 $Log: Firewall.cpp,v $
20 Revision 1.6 2009/04/24 04:55:26 herscher
21 <rdar://problem/3496833> Advertise SMB file sharing via Bonjour
23 Revision 1.5 2009/03/30 20:39:29 herscher
24 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
25 <rdar://problem/5712486> Put in extra defensive checks to prevent NULL pointer dereferencing crash
26 <rdar://problem/5187308> Move build train to Visual Studio 2005
28 Revision 1.4 2006/08/14 23:26:07 cheshire
29 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
31 Revision 1.3 2005/09/29 06:33:54 herscher
32 <rdar://problem/4278931> Fix compilation error when using latest Microsoft Platform SDK.
34 Revision 1.2 2004/09/15 09:39:53 shersche
35 Retry the method INetFwPolicy::get_CurrentProfile on error
37 Revision 1.1 2004/09/13 07:32:31 shersche
38 Wrapper for Windows Firewall API code
43 // <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
45 #if !defined(_WIN32_DCOM)
58 static const int kMaxTries
= 30;
59 static const int kRetrySleepPeriod
= 1 * 1000; // 1 second
63 mDNSFirewallInitialize(OUT INetFwProfile
** fwProfile
)
65 INetFwMgr
* fwMgr
= NULL
;
66 INetFwPolicy
* fwPolicy
= NULL
;
70 _ASSERT(fwProfile
!= NULL
);
74 // Use COM to get a reference to the firewall settings manager. This
75 // call will fail on anything other than XP SP2
77 err
= CoCreateInstance( __uuidof(NetFwMgr
), NULL
, CLSCTX_INPROC_SERVER
, __uuidof(INetFwMgr
), (void**)&fwMgr
);
78 require(SUCCEEDED(err
) && ( fwMgr
!= NULL
), exit
);
80 // Use the reference to get the local firewall policy
82 err
= fwMgr
->get_LocalPolicy(&fwPolicy
);
83 require(SUCCEEDED(err
) && ( fwPolicy
!= NULL
), exit
);
85 // Use the reference to get the extant profile. Empirical evidence
86 // suggests that there is the potential for a race condition when a system
87 // service whose startup type is automatic calls this method.
88 // This is true even when the service declares itself to be dependent
89 // on the firewall service. Re-trying the method will succeed within
94 err
= fwPolicy
->get_CurrentProfile(fwProfile
);
98 Sleep(kRetrySleepPeriod
);
101 while (err
&& (numRetries
++ < kMaxTries
));
103 require(SUCCEEDED(err
), exit
);
109 // Release temporary COM objects
111 if (fwPolicy
!= NULL
)
128 IN INetFwProfile
* fwProfile
131 // Call Release on the COM reference.
133 if (fwProfile
!= NULL
)
135 fwProfile
->Release();
141 mDNSFirewallAppIsEnabled
143 IN INetFwProfile
* fwProfile
,
144 IN
const wchar_t * fwProcessImageFileName
,
145 OUT BOOL
* fwAppEnabled
148 BSTR fwBstrProcessImageFileName
= NULL
;
149 VARIANT_BOOL fwEnabled
;
150 INetFwAuthorizedApplication
* fwApp
= NULL
;
151 INetFwAuthorizedApplications
* fwApps
= NULL
;
152 OSStatus err
= kNoErr
;
154 _ASSERT(fwProfile
!= NULL
);
155 _ASSERT(fwProcessImageFileName
!= NULL
);
156 _ASSERT(fwAppEnabled
!= NULL
);
158 *fwAppEnabled
= FALSE
;
160 // Get the list of authorized applications
162 err
= fwProfile
->get_AuthorizedApplications(&fwApps
);
163 require(SUCCEEDED(err
) && ( fwApps
!= NULL
), exit
);
165 fwBstrProcessImageFileName
= SysAllocString(fwProcessImageFileName
);
166 require_action( ( fwProcessImageFileName
!= NULL
) && ( SysStringLen(fwBstrProcessImageFileName
) > 0 ), exit
, err
= kNoMemoryErr
);
170 err
= fwApps
->Item(fwBstrProcessImageFileName
, &fwApp
);
172 if (SUCCEEDED(err
) && ( fwApp
!= NULL
) )
174 // It's listed, but is it enabled?
176 err
= fwApp
->get_Enabled(&fwEnabled
);
177 require(SUCCEEDED(err
), exit
);
179 if (fwEnabled
!= VARIANT_FALSE
)
183 *fwAppEnabled
= TRUE
;
191 // Deallocate the BSTR
193 if ( fwBstrProcessImageFileName
!= NULL
)
195 SysFreeString(fwBstrProcessImageFileName
);
198 // Release the COM objects
217 IN INetFwProfile
* fwProfile
,
218 IN
const wchar_t * fwProcessImageFileName
,
219 IN
const wchar_t * fwName
223 BSTR fwBstrName
= NULL
;
224 BSTR fwBstrProcessImageFileName
= NULL
;
225 INetFwAuthorizedApplication
* fwApp
= NULL
;
226 INetFwAuthorizedApplications
* fwApps
= NULL
;
229 _ASSERT(fwProfile
!= NULL
);
230 _ASSERT(fwProcessImageFileName
!= NULL
);
231 _ASSERT(fwName
!= NULL
);
233 // First check to see if the application is already authorized.
234 err
= mDNSFirewallAppIsEnabled( fwProfile
, fwProcessImageFileName
, &fwAppEnabled
);
235 require_noerr(err
, exit
);
237 // Only add the application if it isn't enabled
241 // Get the list of authorized applications
243 err
= fwProfile
->get_AuthorizedApplications(&fwApps
);
244 require(SUCCEEDED(err
) && ( fwApps
!= NULL
), exit
);
246 // Create an instance of an authorized application.
248 err
= CoCreateInstance( __uuidof(NetFwAuthorizedApplication
), NULL
, CLSCTX_INPROC_SERVER
, __uuidof(INetFwAuthorizedApplication
), (void**)&fwApp
);
249 require(SUCCEEDED(err
) && ( fwApp
!= NULL
), exit
);
251 fwBstrProcessImageFileName
= SysAllocString(fwProcessImageFileName
);
252 require_action(( fwProcessImageFileName
!= NULL
) && ( SysStringLen(fwBstrProcessImageFileName
) > 0 ), exit
, err
= kNoMemoryErr
);
254 // Set the executable file name
256 err
= fwApp
->put_ProcessImageFileName(fwBstrProcessImageFileName
);
257 require(SUCCEEDED(err
), exit
);
259 fwBstrName
= SysAllocString(fwName
);
260 require_action( ( fwBstrName
!= NULL
) && ( SysStringLen(fwBstrName
) > 0 ), exit
, err
= kNoMemoryErr
);
262 // Set the friendly name
264 err
= fwApp
->put_Name(fwBstrName
);
265 require(SUCCEEDED(err
), exit
);
267 // Now add the application
269 err
= fwApps
->Add(fwApp
);
270 require(SUCCEEDED(err
), exit
);
277 // Deallocate the BSTR objects
279 if ( fwBstrName
!= NULL
)
281 SysFreeString(fwBstrName
);
284 if ( fwBstrProcessImageFileName
!= NULL
)
286 SysFreeString(fwBstrProcessImageFileName
);
289 // Release the COM objects
306 mDNSFirewallIsFileAndPrintSharingEnabled
308 IN INetFwProfile
* fwProfile
,
309 OUT BOOL
* fwServiceEnabled
312 VARIANT_BOOL fwEnabled
;
313 INetFwService
* fwService
= NULL
;
314 INetFwServices
* fwServices
= NULL
;
317 _ASSERT(fwProfile
!= NULL
);
318 _ASSERT(fwServiceEnabled
!= NULL
);
320 *fwServiceEnabled
= FALSE
;
322 // Retrieve the globally open ports collection.
323 err
= fwProfile
->get_Services(&fwServices
);
324 require( SUCCEEDED( err
), exit
);
326 // Attempt to retrieve the globally open port.
327 err
= fwServices
->Item(NET_FW_SERVICE_FILE_AND_PRINT
, &fwService
);
328 require( SUCCEEDED( err
), exit
);
330 // Find out if the globally open port is enabled.
331 err
= fwService
->get_Enabled(&fwEnabled
);
332 require( SUCCEEDED( err
), exit
);
333 if (fwEnabled
!= VARIANT_FALSE
)
335 *fwServiceEnabled
= TRUE
;
340 // Release the globally open port.
341 if (fwService
!= NULL
)
343 fwService
->Release();
346 // Release the globally open ports collection.
347 if (fwServices
!= NULL
)
349 fwServices
->Release();
363 INetFwProfile
* fwProfile
= NULL
;
364 HRESULT comInit
= E_FAIL
;
365 OSStatus err
= kNoErr
;
369 comInit
= CoInitializeEx( 0, COINIT_APARTMENTTHREADED
| COINIT_DISABLE_OLE1DDE
);
371 // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
372 // initialized with a different mode.
374 if (comInit
!= RPC_E_CHANGED_MODE
)
377 require(SUCCEEDED(err
), exit
);
380 // Connect to the firewall
382 err
= mDNSFirewallInitialize(&fwProfile
);
383 require( SUCCEEDED( err
) && ( fwProfile
!= NULL
), exit
);
385 // Add us to the list of exempt programs
387 err
= mDNSFirewallAddApp( fwProfile
, executable
, name
);
388 require_noerr(err
, exit
);
392 // Disconnect from the firewall
394 if ( fwProfile
!= NULL
)
396 mDNSFirewallCleanup(fwProfile
);
401 if (SUCCEEDED(comInit
))
411 mDNSIsFileAndPrintSharingEnabled()
413 INetFwProfile
* fwProfile
= NULL
;
414 HRESULT comInit
= E_FAIL
;
415 BOOL enabled
= FALSE
;
416 OSStatus err
= kNoErr
;
420 comInit
= CoInitializeEx( 0, COINIT_APARTMENTTHREADED
| COINIT_DISABLE_OLE1DDE
);
422 // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
423 // initialized with a different mode.
425 if (comInit
!= RPC_E_CHANGED_MODE
)
428 require(SUCCEEDED(err
), exit
);
431 // Connect to the firewall
433 err
= mDNSFirewallInitialize(&fwProfile
);
434 require( SUCCEEDED( err
) && ( fwProfile
!= NULL
), exit
);
436 err
= mDNSFirewallIsFileAndPrintSharingEnabled( fwProfile
, &enabled
);
437 require_noerr( err
, exit
);
441 // Disconnect from the firewall
443 if ( fwProfile
!= NULL
)
445 mDNSFirewallCleanup(fwProfile
);
450 if (SUCCEEDED(comInit
))