xref: /reactos/dll/cpl/inetcpl/security.c (revision 14d3b53c)
1 /*
2  * Internet control panel applet: security propsheet
3  *
4  * Copyright 2011 Detlef Riekenberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  */
21 
22 #define COBJMACROS
23 #define CONST_VTABLE
24 
25 #include <stdarg.h>
26 #include <windef.h>
27 #include <winbase.h>
28 #include <winuser.h>
29 #include <prsht.h>
30 #include "commctrl.h"
31 
32 #include "ole2.h"
33 #include "urlmon.h"
34 #include "initguid.h"
35 #include "winreg.h"
36 #include "shlwapi.h"
37 
38 #include "inetcpl.h"
39 #include "wine/debug.h"
40 #include "wine/heap.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(inetcpl);
43 
44 typedef struct secdlg_data_s {
45     HWND hsec;  /* security propsheet */
46     HWND hlv;   /* listview */
47     HWND htb;   /* trackbar */
48     IInternetSecurityManager *sec_mgr;
49     IInternetZoneManager *zone_mgr;
50     DWORD zone_enumerator;
51     DWORD num_zones;
52     ZONEATTRIBUTES *zone_attr;
53     DWORD *zones;
54     DWORD *levels;
55     HIMAGELIST himages;
56     DWORD last_lv_index;
57     DWORD last_level;
58 } secdlg_data;
59 
60 #define NUM_TRACKBAR_POS 5
61 
62 static DWORD url_templates[] = {URLTEMPLATE_CUSTOM,
63                                 URLTEMPLATE_LOW,
64                                 URLTEMPLATE_MEDLOW,
65                                 URLTEMPLATE_MEDIUM,
66                                 URLTEMPLATE_MEDHIGH,
67                                 URLTEMPLATE_HIGH};
68 
69 /*********************************************************************
70  * index_from_urltemplate [internal]
71  *
72  */
73 static DWORD index_from_urltemplate(URLTEMPLATE value)
74 {
75 
76     DWORD index = ARRAY_SIZE(url_templates);
77 
78     while((index > 0) && (url_templates[index-1] != value))
79         index--;
80 
81     index--; /* table entries are 0 based */
82     if (!index && value)
83         FIXME("URLTEMPLATE 0x%x not supported\n", value);
84 
85     TRACE("URLTEMPLATE 0x%08x=> Level %d\n", value, index);
86     return index;
87 }
88 
89 /*********************************************************************
90  * update_security_level [internal]
91  *
92  */
93 static void update_security_level(secdlg_data *sd, DWORD lv_index, DWORD tb_index)
94 {
95     WCHAR name[512];
96     DWORD current_index;
97 
98     TRACE("(%p, lv_index: %u, tb_index: %u)\n", sd, lv_index, tb_index);
99 
100     if ((sd->levels[lv_index] != sd->last_level) || (tb_index > 0)) {
101         /* show or hide the trackbar */
102         if (!sd->levels[lv_index] || !sd->last_level)
103             ShowWindow(sd->htb, sd->levels[lv_index] ? SW_NORMAL : SW_HIDE);
104 
105         current_index = (tb_index > 0) ? tb_index : index_from_urltemplate(sd->levels[lv_index]);
106 
107         name[0] = 0;
108         LoadStringW(hcpl, IDS_SEC_LEVEL0 + current_index, name, ARRAY_SIZE(name));
109         TRACE("new level #%d: %s\n", current_index, debugstr_w(name));
110         SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL), name);
111 
112         name[0] = 0;
113         LoadStringW(hcpl, IDS_SEC_LEVEL0_INFO + (current_index * 0x10), name, ARRAY_SIZE(name));
114         TRACE("new level info: %s\n", debugstr_w(name));
115         SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL_INFO), name);
116 
117         if (current_index)
118             SendMessageW(sd->htb, TBM_SETPOS, TRUE, NUM_TRACKBAR_POS - current_index);
119 
120         sd->last_level = sd->levels[lv_index];
121 
122     }
123 }
124 
125 /*********************************************************************
126  * update_zone_info [internal]
127  *
128  */
129 static void update_zone_info(secdlg_data *sd, DWORD lv_index)
130 {
131     ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
132     WCHAR name[MAX_PATH];
133     DWORD len;
134 
135     SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_ZONE_INFO), za->szDescription);
136 
137     len = LoadStringW(hcpl, IDS_SEC_SETTINGS, name, ARRAY_SIZE(name));
138     lstrcpynW(&name[len], za->szDisplayName, ARRAY_SIZE(name) - len - 1);
139 
140     TRACE("new title: %s\n", debugstr_w(name));
141     SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_GROUP), name);
142 
143     update_security_level(sd, lv_index, 0);
144     sd->last_lv_index = lv_index;
145 }
146 
147 /*********************************************************************
148  * add_zone_to_listview [internal]
149  *
150  */
151 static void add_zone_to_listview(secdlg_data *sd, DWORD *pindex, DWORD zone)
152 {
153     DWORD lv_index = *pindex;
154     ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
155     LVITEMW lvitem;
156     HRESULT hr;
157     INT iconid = 0;
158     HMODULE hdll = NULL;
159     WCHAR * ptr;
160     HICON icon;
161 
162     TRACE("item %d (zone %d)\n", lv_index, zone);
163 
164     sd->zones[lv_index] = zone;
165 
166     memset(&lvitem, 0, sizeof(LVITEMW));
167     memset(za, 0, sizeof(ZONEATTRIBUTES));
168     za->cbSize = sizeof(ZONEATTRIBUTES);
169     hr = IInternetZoneManager_GetZoneAttributes(sd->zone_mgr, zone, za);
170     if (SUCCEEDED(hr)) {
171         TRACE("displayname: %s\n", debugstr_w(za->szDisplayName));
172         TRACE("description: %s\n", debugstr_w(za->szDescription));
173         TRACE("minlevel: 0x%x, recommended: 0x%x, current: 0x%x (flags: 0x%x)\n", za->dwTemplateMinLevel,
174              za->dwTemplateRecommended, za->dwTemplateCurrentLevel, za->dwFlags);
175 
176         if (za->dwFlags & ZAFLAGS_NO_UI ) {
177             TRACE("item %d (zone %d): UI disabled for %s\n", lv_index, zone, debugstr_w(za->szDisplayName));
178             return;
179         }
180 
181         sd->levels[lv_index] = za->dwTemplateCurrentLevel;
182 
183         lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
184         lvitem.iItem = lv_index;
185         lvitem.iSubItem = 0;
186         lvitem.pszText = za->szDisplayName;
187         lvitem.lParam = (LPARAM) zone;
188 
189         /* format is "filename.ext#iconid" */
190         ptr = StrChrW(za->szIconPath, '#');
191         if (ptr) {
192             *ptr = 0;
193             ptr++;
194             iconid = StrToIntW(ptr);
195             hdll = LoadLibraryExW(za->szIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
196             TRACE("%p: icon #%d from %s\n", hdll, iconid, debugstr_w(za->szIconPath));
197 
198             icon = LoadImageW(hdll, MAKEINTRESOURCEW(iconid), IMAGE_ICON, GetSystemMetrics(SM_CXICON),
199                               GetSystemMetrics(SM_CYICON), LR_SHARED);
200 
201             if (!icon) {
202                 FIXME("item %d (zone %d): missing icon #%d in %s\n", lv_index, zone, iconid, debugstr_w(za->szIconPath));
203             }
204 
205             /* the failure result (NULL) from LoadImageW let ImageList_AddIcon fail
206                with -1, which is reused in ListView_InsertItemW to disable the image */
207             lvitem.iImage = ImageList_AddIcon(sd->himages, icon);
208         }
209         else
210             FIXME("item %d (zone %d): malformed szIconPath %s\n", lv_index, zone, debugstr_w(za->szIconPath));
211 
212         if (ListView_InsertItemW(sd->hlv, &lvitem) >= 0) {
213             /* activate first item in the listview */
214             if (! lv_index) {
215                 lvitem.state = LVIS_FOCUSED | LVIS_SELECTED;
216                 lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
217                 SendMessageW(sd->hlv, LVM_SETITEMSTATE, 0, (LPARAM) &lvitem);
218                 sd->last_level = ~0;
219                 update_zone_info(sd, lv_index);
220             }
221             (*pindex)++;
222         }
223         FreeLibrary(hdll);
224     }
225     else
226         FIXME("item %d (zone %d): GetZoneAttributes failed with 0x%x\n", lv_index, zone, hr);
227 }
228 
229 /*********************************************************************
230  * security_cleanup_zones [internal]
231  *
232  */
233 static void security_cleanup_zones(secdlg_data *sd)
234 {
235     if (sd->zone_enumerator) {
236         IInternetZoneManager_DestroyZoneEnumerator(sd->zone_mgr, sd->zone_enumerator);
237     }
238 
239     if (sd->zone_mgr) {
240         IInternetZoneManager_Release(sd->zone_mgr);
241     }
242 
243     if (sd->sec_mgr) {
244         IInternetSecurityManager_Release(sd->sec_mgr);
245     }
246 }
247 
248 /*********************************************************************
249  * security_enum_zones [internal]
250  *
251  */
252 static HRESULT security_enum_zones(secdlg_data * sd)
253 {
254     HRESULT hr;
255 
256     hr = CoInternetCreateSecurityManager(NULL, &sd->sec_mgr, 0);
257     if (SUCCEEDED(hr)) {
258         hr = CoInternetCreateZoneManager(NULL, &sd->zone_mgr, 0);
259         if (SUCCEEDED(hr)) {
260             hr = IInternetZoneManager_CreateZoneEnumerator(sd->zone_mgr, &sd->zone_enumerator, &sd->num_zones, 0);
261         }
262     }
263     return hr;
264 }
265 
266 /*********************************************************************
267  * security_on_destroy [internal]
268  *
269  * handle WM_NCDESTROY
270  *
271  */
272 static INT_PTR security_on_destroy(secdlg_data * sd)
273 {
274     TRACE("(%p)\n", sd);
275 
276     heap_free(sd->zone_attr);
277     heap_free(sd->zones);
278 #ifndef __REACTOS__
279     if (sd->himages) {
280         SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
281         ImageList_Destroy(sd->himages);
282     }
283 #endif
284 
285     security_cleanup_zones(sd);
286     SetWindowLongPtrW(sd->hsec, DWLP_USER, 0);
287     heap_free(sd);
288     return TRUE;
289 }
290 
291 /*********************************************************************
292  * security_on_initdialog [internal]
293  *
294  * handle WM_INITDIALOG
295  *
296  */
297 static INT_PTR security_on_initdialog(HWND hsec)
298 {
299     secdlg_data *sd;
300     HRESULT hr;
301     DWORD current_zone;
302     DWORD lv_index = 0;
303     DWORD i;
304 
305     sd = heap_alloc_zero(sizeof(secdlg_data));
306     SetWindowLongPtrW(hsec, DWLP_USER, (LONG_PTR) sd);
307     if (!sd) {
308         return FALSE;
309     }
310 
311     sd->hsec = hsec;
312     sd->hlv = GetDlgItem(hsec, IDC_SEC_LISTVIEW);
313     sd->htb = GetDlgItem(hsec, IDC_SEC_TRACKBAR);
314 
315     EnableWindow(sd->htb, FALSE); /* not changeable yet */
316 
317     TRACE("(%p)   (data: %p, listview: %p, trackbar: %p)\n", hsec, sd, sd->hlv, sd->htb);
318 
319     SendMessageW(sd->htb, TBM_SETRANGE, FALSE, MAKELONG(0, NUM_TRACKBAR_POS - 1));
320     SendMessageW(sd->htb, TBM_SETTICFREQ, 1, 0 );
321 
322     /* Create the image lists for the listview */
323     sd->himages = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1);
324 
325     TRACE("using imagelist: %p\n", sd->himages);
326     if (!sd->himages) {
327         ERR("ImageList_Create failed!\n");
328         return FALSE;
329     }
330     SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)sd->himages);
331 
332     hr = security_enum_zones(sd);
333     if (FAILED(hr)) {
334         ERR("got 0x%x\n", hr);
335         security_on_destroy(sd);
336         return FALSE;
337     }
338 
339     TRACE("found %d zones\n", sd->num_zones);
340 
341     /* remember ZONEATTRIBUTES for a listview entry */
342     sd->zone_attr = heap_alloc(sizeof(ZONEATTRIBUTES) * sd->num_zones);
343     if (!sd->zone_attr) {
344         security_on_destroy(sd);
345         return FALSE;
346     }
347 
348     /* remember zone number and current security level for a listview entry */
349     sd->zones = heap_alloc((sizeof(DWORD) + sizeof(DWORD)) * sd->num_zones);
350     if (!sd->zones) {
351         security_on_destroy(sd);
352         return FALSE;
353     }
354     sd->levels = &sd->zones[sd->num_zones];
355 
356     /* use the same order as visible with native inetcpl.cpl */
357     add_zone_to_listview(sd, &lv_index, URLZONE_INTERNET);
358     add_zone_to_listview(sd, &lv_index, URLZONE_INTRANET);
359     add_zone_to_listview(sd, &lv_index, URLZONE_TRUSTED);
360     add_zone_to_listview(sd, &lv_index, URLZONE_UNTRUSTED);
361 
362     for (i = 0; i < sd->num_zones; i++)
363     {
364         hr = IInternetZoneManager_GetZoneAt(sd->zone_mgr, sd->zone_enumerator, i, &current_zone);
365         if (SUCCEEDED(hr) && (current_zone != (DWORD)URLZONE_INVALID)) {
366             if (!current_zone || (current_zone > URLZONE_UNTRUSTED)) {
367                 add_zone_to_listview(sd, &lv_index, current_zone);
368             }
369         }
370     }
371     return TRUE;
372 }
373 
374 /*********************************************************************
375  * security_on_notify [internal]
376  *
377  * handle WM_NOTIFY
378  *
379  */
380 static INT_PTR security_on_notify(secdlg_data *sd, WPARAM wparam, LPARAM lparam)
381 {
382     NMLISTVIEW *nm;
383 
384     nm = (NMLISTVIEW *) lparam;
385     switch (nm->hdr.code)
386     {
387         case LVN_ITEMCHANGED:
388             TRACE("LVN_ITEMCHANGED (0x%lx, 0x%lx) from %p with code: %d (item: %d, uNewState: %u)\n",
389                     wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code, nm->iItem, nm->uNewState);
390             if ((nm->uNewState & LVIS_SELECTED) == LVIS_SELECTED) {
391                 update_zone_info(sd, nm->iItem);
392             }
393             break;
394 
395         case PSN_APPLY:
396             TRACE("PSN_APPLY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
397                     nm->hdr.hwndFrom, nm->hdr.code);
398             break;
399 
400         default:
401             TRACE("WM_NOTIFY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
402                     nm->hdr.hwndFrom, nm->hdr.code);
403 
404     }
405     return FALSE;
406 }
407 
408 /*********************************************************************
409  * security_dlgproc [internal]
410  *
411  */
412 INT_PTR CALLBACK security_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
413 {
414     secdlg_data *sd;
415 
416     if (msg == WM_INITDIALOG) {
417         return security_on_initdialog(hwnd);
418     }
419 
420     sd = (secdlg_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
421     if (sd) {
422         switch (msg)
423         {
424             case WM_NOTIFY:
425                 return security_on_notify(sd, wparam, lparam);
426 
427             case WM_NCDESTROY:
428                 return security_on_destroy(sd);
429 
430             default:
431                 /* do not flood the log */
432                 if ((msg == WM_SETCURSOR) || (msg == WM_NCHITTEST) ||
433                     (msg == WM_MOUSEMOVE) || (msg == WM_MOUSEACTIVATE) || (msg == WM_PARENTNOTIFY))
434                     return FALSE;
435 
436                 TRACE("(%p, 0x%08x/%03d, 0x%08lx, 0x%08lx)\n", hwnd, msg, msg, wparam, lparam);
437         }
438     }
439     return FALSE;
440 }
441