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