Windows: remove extraneous "pingCount" format param
[openafs.git] / src / WINNT / afsd / afsicf.cpp
1 /*
2  * Copyright 2004 by the Massachusetts Institute of Technology
3  *
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software and its
7  * documentation for any purpose and without fee is hereby granted,
8  * provided that the above copyright notice appear in all copies and that
9  * both that copyright notice and this permission notice appear in
10  * supporting documentation, and that the name of the Massachusetts
11  * Institute of Technology (M.I.T.) not be used in advertising or publicity
12  * pertaining to distribution of the software without specific, written
13  * prior permission.
14  *
15  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17  * M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21  * SOFTWARE.
22  *
23  */
24
25 /*
26  * Copyright 2011 by Your File System, Inc.
27  */
28
29 #define _WIN32_DCOM
30 #include <windows.h>
31 #include <netfw.h>
32 #include <objbase.h>
33 #include <oleauto.h>
34 #include "afsicf.h"
35 #include <wchar.h>
36
37 #ifdef TESTMAIN
38 #include<stdio.h>
39 #pragma comment(lib,"ole32.lib")
40 #pragma comment(lib,"oleaut32.lib")
41 #define DEBUGOUT(x) printf(x)
42 #define DEBUGOUTW(x) wprintf(x)
43 #else
44 #define DEBUGOUT(x) OutputDebugString(x)
45 #define DEBUGOUTW(x) OutputDebugStringW(x)
46 #endif
47
48 /* an IPv4, enabled port with global scope */
49 struct global_afs_port_type {
50     LPWSTR      name;
51     LONG        n_port;
52     LPWSTR      str_port;
53     NET_FW_IP_PROTOCOL protocol;
54 };
55
56 typedef struct global_afs_port_type global_afs_port_t;
57
58 global_afs_port_t afs_clientPorts[] = {
59     { L"AFS CacheManager Callback (UDP)", 7001, L"7001", NET_FW_IP_PROTOCOL_UDP }
60 #ifdef AFS_TCP
61 ,   { L"AFS CacheManager Callback (TCP)", 7001, L"7001", NET_FW_IP_PROTOCOL_TCP }
62 #endif
63 };
64
65 global_afs_port_t afs_serverPorts[] = {
66     { L"AFS File Server (UDP)", 7000, L"7000", NET_FW_IP_PROTOCOL_UDP },
67 #ifdef AFS_TCP
68     { L"AFS File Server (TCP)", 7000, L"7000", NET_FW_IP_PROTOCOL_TCP },
69 #endif
70     { L"AFS User & Group Database (UDP)", 7002, L"7002", NET_FW_IP_PROTOCOL_UDP },
71 #ifdef AFS_TCP
72     { L"AFS User & Group Database (TCP)", 7002, L"7002", NET_FW_IP_PROTOCOL_TCP },
73 #endif
74     { L"AFS Volume Location Database (UDP)", 7003, L"7003", NET_FW_IP_PROTOCOL_UDP },
75 #ifdef AFS_TCP
76     { L"AFS Volume Location Database (TCP)", 7003, L"7003", NET_FW_IP_PROTOCOL_TCP },
77 #endif
78     { L"AFS/Kerberos Authentication (UDP)", 7004, L"7004", NET_FW_IP_PROTOCOL_UDP },
79 #ifdef AFS_TCP
80     { L"AFS/Kerberos Authentication (TCP)", 7004, L"7004", NET_FW_IP_PROTOCOL_TCP },
81 #endif
82     { L"AFS Volume Mangement (UDP)", 7005, L"7005", NET_FW_IP_PROTOCOL_UDP },
83 #ifdef AFS_TCP
84     { L"AFS Volume Mangement (TCP)", 7005, L"7005", NET_FW_IP_PROTOCOL_TCP },
85 #endif
86     { L"AFS Error Interpretation (UDP)", 7006, L"7006", NET_FW_IP_PROTOCOL_UDP },
87 #ifdef AFS_TCP
88     { L"AFS Error Interpretation (TCP)", 7006, L"7006", NET_FW_IP_PROTOCOL_TCP },
89 #endif
90     { L"AFS Basic Overseer (UDP)", 7007, L"7007", NET_FW_IP_PROTOCOL_UDP },
91 #ifdef AFS_TCP
92     { L"AFS Basic Overseer (TCP)", 7007, L"7007", NET_FW_IP_PROTOCOL_TCP },
93 #endif
94     { L"AFS Server-to-server Updater (UDP)", 7008, L"7008", NET_FW_IP_PROTOCOL_UDP },
95 #ifdef AFS_TCP
96     { L"AFS Server-to-server Updater (TCP)", 7008, L"7008", NET_FW_IP_PROTOCOL_TCP },
97 #endif
98     { L"AFS Remote Cache Manager (UDP)", 7009, L"7009", NET_FW_IP_PROTOCOL_UDP }
99 #ifdef AFS_TCP
100 ,   { L"AFS Remote Cache Manager (TCP)", 7009, L"7009", NET_FW_IP_PROTOCOL_TCP }
101 #endif
102 };
103
104 HRESULT icf_CheckAndAddPorts2(WCHAR * wServiceName, global_afs_port_t * ports, int nPorts)
105 {
106     INetFwPolicy2 *pNetFwPolicy2 = NULL;
107     INetFwRules *pFwRules = NULL;
108     INetFwRule *pFwRule = NULL;
109     WCHAR wFilename[1024] = L"C:\\Program Files\\OpenAFS\\Client\\Program\\afsd_service.exe";
110
111     long CurrentProfilesBitMask = 0;
112     int  i;
113
114 #ifndef TESTMAIN
115     GetModuleFileNameW(NULL, wFilename, 1024);
116 #endif
117
118     BSTR bstrRuleGroup = SysAllocString(L"OpenAFS Firewall Rules");
119     BSTR bstrRuleApplication = SysAllocString(wFilename);
120     BSTR bstrRuleService = SysAllocString(wServiceName);
121     BSTR bstrInterfaceTypes = SysAllocString(L"all");
122
123     HRESULT hrComInit = S_OK;
124     HRESULT hr = S_OK;
125
126     // Retrieve INetFwPolicy2
127     hr = CoCreateInstance( __uuidof(NetFwPolicy2),
128                            NULL,
129                            CLSCTX_INPROC_SERVER,
130                            __uuidof(INetFwPolicy2),
131                            (void**)&pNetFwPolicy2);
132     if (FAILED(hr))
133     {
134         DEBUGOUT(("Can't create NetFwPolicy2\n"));
135         goto Cleanup;
136     }
137
138     // Retrieve INetFwRules
139     hr = pNetFwPolicy2->get_Rules(&pFwRules);
140     if (FAILED(hr))
141     {
142         DEBUGOUT(("get_Rules failed\n"));
143         goto Cleanup;
144     }
145
146     if ( nPorts == 0 )
147         DEBUGOUT(("No port specified\n"));
148
149     for ( i=0; i < nPorts; i++)
150     {
151         BSTR bstrRuleName = SysAllocString(ports[i].name);
152         BSTR bstrRuleDescription = SysAllocString(ports[i].name);
153         BSTR bstrRuleLPorts = SysAllocString(ports[i].str_port);
154
155         hr = pFwRules->Item(bstrRuleName, &pFwRule);
156         if (FAILED(hr))
157         {
158             // Create a new Firewall Rule object.
159             hr = CoCreateInstance( __uuidof(NetFwRule),
160                                    NULL,
161                                    CLSCTX_INPROC_SERVER,
162                                    __uuidof(INetFwRule),
163                                    (void**)&pFwRule);
164             if (SUCCEEDED(hr))
165             {
166                 // Populate the Firewall Rule object
167                 pFwRule->put_Name(bstrRuleName);
168                 pFwRule->put_Description(bstrRuleDescription);
169                 pFwRule->put_ApplicationName(bstrRuleApplication);
170
171                 // Add the Firewall Rule
172                 hr = pFwRules->Add(pFwRule);
173                 if (FAILED(hr))
174                 {
175                     DEBUGOUT(("Advanced Firewall Rule Add failed\n"));
176                 }
177                 else
178                 {
179                     DEBUGOUT(("Advanced Firewall Rule Add successful\n"));
180
181                     //
182                     // Do not assign the service name to the rule.
183                     // Only specify the executable name. According to feedback
184                     // in openafs-info, the service name filter blocks the rule.
185                     //
186                     pFwRule->put_ServiceName(NULL);
187                     pFwRule->put_Protocol(ports[i].protocol);
188                     pFwRule->put_LocalPorts(bstrRuleLPorts);
189                     pFwRule->put_Grouping(bstrRuleGroup);
190                     pFwRule->put_Profiles(NET_FW_PROFILE2_ALL);
191                     pFwRule->put_Action(NET_FW_ACTION_ALLOW);
192                     pFwRule->put_Enabled(VARIANT_TRUE);
193                     pFwRule->put_EdgeTraversal(VARIANT_TRUE);
194                     pFwRule->put_InterfaceTypes(bstrInterfaceTypes);
195                 }
196             }
197             else
198             {
199                 DEBUGOUT(("CoCreateInstance INetFwRule failed\n"));
200             }
201         }
202         else
203         {
204             DEBUGOUT(("INetFwRule already exists\n"));
205
206             hr = pFwRule->put_ServiceName(NULL);
207             if (SUCCEEDED(hr))
208             {
209                 DEBUGOUT(("INetFwRule Service Name Updated\n"));
210             }
211
212             hr = pFwRule->put_ApplicationName(bstrRuleApplication);
213             if (SUCCEEDED(hr))
214             {
215                 DEBUGOUT(("INetFwRule Application Name Updated\n"));
216             }
217
218             hr = pFwRule->put_EdgeTraversal(VARIANT_TRUE);
219             if (SUCCEEDED(hr))
220             {
221                 DEBUGOUT(("INetFwRule Edge Traversal Updated\n"));
222             }
223
224             hr = pFwRule->put_InterfaceTypes(bstrInterfaceTypes);
225             if (SUCCEEDED(hr))
226             {
227                 DEBUGOUT(("INetFwRule Interface Types Updated\n"));
228             }
229
230             hr = pFwRule->put_Protocol(ports[i].protocol);
231             if (SUCCEEDED(hr))
232             {
233                 DEBUGOUT(("INetFwRule Interface Protocol Updated\n"));
234             }
235
236             hr = pFwRule->put_LocalPorts(bstrRuleLPorts);
237             if (SUCCEEDED(hr))
238             {
239                 DEBUGOUT(("INetFwRule Interface Local Ports Updated\n"));
240             }
241
242             hr = pFwRule->put_Grouping(bstrRuleGroup);
243             if (SUCCEEDED(hr))
244             {
245                 DEBUGOUT(("INetFwRule Interface Grouping Updated\n"));
246             }
247
248             hr = pFwRule->put_Action(NET_FW_ACTION_ALLOW);
249             if (SUCCEEDED(hr))
250             {
251                 DEBUGOUT(("INetFwRule Interface Action Updated\n"));
252             }
253         }
254
255         SysFreeString(bstrRuleName);
256         SysFreeString(bstrRuleDescription);
257         SysFreeString(bstrRuleLPorts);
258     }
259
260   Cleanup:
261
262     // Free BSTR's
263     SysFreeString(bstrRuleGroup);
264     SysFreeString(bstrRuleApplication);
265     SysFreeString(bstrRuleService);
266     SysFreeString(bstrInterfaceTypes);
267
268     // Release the INetFwRule object
269     if (pFwRule != NULL)
270     {
271         pFwRule->Release();
272     }
273
274     // Release the INetFwRules object
275     if (pFwRules != NULL)
276     {
277         pFwRules->Release();
278     }
279
280     // Release the INetFwPolicy2 object
281     if (pNetFwPolicy2 != NULL)
282     {
283         pNetFwPolicy2->Release();
284     }
285
286     // Uninitialize COM.
287     if (SUCCEEDED(hrComInit))
288     {
289         CoUninitialize();
290     }
291
292     return 0;
293 }
294
295
296 HRESULT icf_OpenFirewallProfile(INetFwProfile ** fwProfile)
297 {
298     HRESULT hr = S_OK;
299     INetFwMgr* fwMgr = NULL;
300     INetFwPolicy* fwPolicy = NULL;
301
302     *fwProfile = NULL;
303
304     // Create an instance of the firewall settings manager.
305     hr = CoCreateInstance(
306             __uuidof(NetFwMgr),
307             NULL,
308             CLSCTX_INPROC_SERVER,
309             __uuidof(INetFwMgr),
310             reinterpret_cast<void**>(static_cast<INetFwMgr**>(&fwMgr))
311             );
312     if (FAILED(hr))
313     {
314         DEBUGOUT(("Can't create fwMgr\n"));
315         goto error;
316     }
317
318     // Retrieve the local firewall policy.
319     hr = fwMgr->get_LocalPolicy(&fwPolicy);
320     if (FAILED(hr))
321     {
322         DEBUGOUT(("Cant get local policy\n"));
323         goto error;
324     }
325
326     // Retrieve the firewall profile currently in effect.
327     hr = fwPolicy->get_CurrentProfile(fwProfile);
328     if (FAILED(hr))
329     {
330         DEBUGOUT(("Can't get current profile\n"));
331         goto error;
332     }
333
334   error:
335
336     // Release the local firewall policy.
337     if (fwPolicy != NULL)
338     {
339         fwPolicy->Release();
340     }
341
342     // Release the firewall settings manager.
343     if (fwMgr != NULL)
344     {
345         fwMgr->Release();
346     }
347
348     return hr;
349 }
350
351 HRESULT icf_CheckAndAddPorts(INetFwProfile * fwProfile, global_afs_port_t * ports, int nPorts) {
352     INetFwOpenPorts * fwPorts = NULL;
353     INetFwOpenPort * fwPort = NULL;
354     HRESULT hr;
355     HRESULT rhr = S_OK; /* return value */
356     int i = 0;
357
358     hr = fwProfile->get_GloballyOpenPorts(&fwPorts);
359     if (FAILED(hr)) {
360         // Abort!
361         DEBUGOUT(("Can't get globallyOpenPorts\n"));
362         rhr = hr;
363         goto cleanup;
364     }
365
366     // go through the supplied ports
367     for (i=0; i<nPorts; i++) {
368         VARIANT_BOOL vbEnabled;
369         BSTR bstName = NULL;
370         BOOL bCreate = FALSE;
371         fwPort = NULL;
372
373         hr = fwPorts->Item(ports[i].n_port, ports[i].protocol, &fwPort);
374         if (SUCCEEDED(hr)) {
375             DEBUGOUTW((L"Found port for %S\n",ports[i].name));
376             hr = fwPort->get_Enabled(&vbEnabled);
377             if (SUCCEEDED(hr)) {
378                 if ( vbEnabled == VARIANT_FALSE ) {
379                     hr = fwPort->put_Enabled(VARIANT_TRUE);
380                     if (FAILED(hr)) {
381                         // failed. Mark as failure. Don't try to create the port either.
382                         rhr = hr;
383                     }
384                 } // else we are fine
385             } else {
386                 // Something is wrong with the port.
387                 // We try to create a new one thus overriding this faulty one.
388                 bCreate = TRUE;
389             }
390             fwPort->Release();
391             fwPort = NULL;
392         } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
393             DEBUGOUTW((L"Port not found for %S\n", ports[i].name));
394             bCreate = TRUE;
395         }
396
397         if (bCreate) {
398             DEBUGOUTW((L"Trying to create port %S\n",ports[i].name));
399             hr = CoCreateInstance( __uuidof(NetFwOpenPort),
400                                    NULL,
401                                    CLSCTX_INPROC_SERVER,
402                                    __uuidof(INetFwOpenPort),
403                                    reinterpret_cast<void**>
404                                    (static_cast<INetFwOpenPort**>(&fwPort))
405                                    );
406
407             if (FAILED(hr)) {
408                 DEBUGOUT(("Can't create port\n"));
409                 rhr = hr;
410             } else {
411                 DEBUGOUT(("Created port\n"));
412                 hr = fwPort->put_IpVersion( NET_FW_IP_VERSION_ANY );
413                 if (FAILED(hr)) {
414                     DEBUGOUT(("Can't set IpVersion\n"));
415                     rhr = hr;
416                     goto abandon_port;
417                 }
418
419                 hr = fwPort->put_Port( ports[i].n_port );
420                 if (FAILED(hr)) {
421                     DEBUGOUT(("Can't set Port\n"));
422                     rhr = hr;
423                     goto abandon_port;
424                 }
425
426                 hr = fwPort->put_Protocol( ports[i].protocol );
427                 if (FAILED(hr)) {
428                     DEBUGOUT(("Can't set Protocol\n"));
429                     rhr = hr;
430                     goto abandon_port;
431                 }
432
433                 hr = fwPort->put_Scope( NET_FW_SCOPE_ALL );
434                 if (FAILED(hr)) {
435                     DEBUGOUT(("Can't set Scope\n"));
436                     rhr = hr;
437                     goto abandon_port;
438                 }
439
440                 bstName = SysAllocString( ports[i].name );
441
442                 if (SysStringLen(bstName) == 0) {
443                     rhr = E_OUTOFMEMORY;
444                 } else {
445                     hr = fwPort->put_Name( bstName );
446                     if (FAILED(hr)) {
447                         DEBUGOUT(("Can't set Name\n"));
448                         rhr = hr;
449                         SysFreeString( bstName );
450                         goto abandon_port;
451                     }
452                 }
453
454                 SysFreeString( bstName );
455
456                 hr = fwPorts->Add( fwPort );
457                 if (FAILED(hr)) {
458                     DEBUGOUT(("Can't add port\n"));
459                     rhr = hr;
460                 } else
461                     DEBUGOUT(("Added port\n"));
462
463               abandon_port:
464                 fwPort->Release();
465             }
466         }
467     } // loop through ports
468
469     fwPorts->Release();
470
471   cleanup:
472
473     if (fwPorts != NULL)
474         fwPorts->Release();
475
476     return rhr;
477 }
478
479 long icf_CheckAndAddAFSPorts(int port) {
480     HRESULT hr;
481     BOOL coInitialized = FALSE;
482     INetFwProfile * fwProfile = NULL;
483     global_afs_port_t * ports;
484     WCHAR * wServiceName;
485     int nports;
486     long code = 0;
487
488     if (port == AFS_PORTSET_SERVER) {
489         ports = afs_serverPorts;
490         nports = sizeof(afs_serverPorts) / sizeof(*afs_serverPorts);
491         wServiceName = L"TransarcAFSServer";;
492     } else /* an actual client port */ {
493         WCHAR str_port[32];
494
495         if (_snwprintf_s(str_port, 32, 31, L"%u", port) < 0) {
496             DEBUGOUT(("Invalid port set\n"));
497             return 1; /* Invalid port set */
498         }
499
500         ports = afs_clientPorts;
501         nports = sizeof(afs_clientPorts) / sizeof(*afs_clientPorts);
502
503         afs_clientPorts[0].n_port = port;
504         afs_clientPorts[0].str_port = str_port;
505         wServiceName = L"TransarcAFSDaemon";
506     }
507     hr = CoInitializeEx( NULL,
508                          COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE
509                          );
510
511     if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
512     {
513        coInitialized = TRUE;
514     }
515     // not necessarily catastrophic if the call failed.  We'll try to
516     // continue as if it succeeded.
517
518     hr = icf_CheckAndAddPorts2(wServiceName, ports, nports);
519     if (FAILED(hr)) {
520         DEBUGOUT(("INetFwProfile2 failed, trying INetFwProfile\n"));
521         hr = icf_OpenFirewallProfile(&fwProfile);
522         if (FAILED(hr)) {
523             // Ok. That didn't work.  This could be because the machine we
524             // are running on doesn't have Windows Firewall.  We'll return
525             // a failure to the caller, which shouldn't be taken to mean
526             // it's catastrophic.
527             DEBUGOUT(("Can't open Firewall profile\n"));
528             code = 2;
529             goto cleanup;
530         }
531
532         // Now that we have a firewall profile, we can start checking
533         // and adding the ports that we want.
534         hr = icf_CheckAndAddPorts(fwProfile, ports, nports);
535         if (FAILED(hr))
536             code = 3;
537     }
538
539   cleanup:
540     if (coInitialized) {
541         CoUninitialize();
542     }
543
544     return code;
545 }
546
547
548 #ifdef TESTMAIN
549 int main(int argc, char **argv) {
550     printf("Starting...\n");
551     if (icf_CheckAndAddAFSPorts(7001))
552         printf("Failed\n");
553     else
554         printf("Succeeded\n");
555     printf("Done\n");
556     return 0;
557 }
558 #endif