* Sync up to trunk head (r65120).
[reactos.git] / dll / cpl / inetcpl / security.c
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 }